diff --git a/CHANGELOG.md b/CHANGELOG.md index 1f94c79..18caf9e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ All notable changes are documented here. This project follows Semantic Versionin ### Fixed +- Preserved ignored-file path identity across platforms when enforcing immutable workspace alignment. POSIX filenames containing literal backslashes are no longer rewritten as directory separators, so a distinct ignored runtime input such as `coverage\proof.lcov` cannot alias an explicitly allowed `coverage/proof.lcov` data artifact and bypass the pre-execution fail-closed gate. - Failed closed on unattributed targeted-runner process failures even when another qualified batch target is unavailable. An unavailable target can no longer act as a sink that lets unrelated observed passes survive an ambiguous process-level failure; only explicitly failed targets retain localized failure attribution. - Failed closed on deletion-only zero-context hunks when attributing current changed symbols and call references. Git represents a deletion-only hunk with a zero-length new-side range anchored to a neighboring current line; ProofDiff now reconciles reconstructed current-line spans with Git numstat additions before treating those anchors as changed current code. - Preserved precise changed-line hunks across renames by scoping per-file Git diffs to both the previous and current path. This prevents a rename with content edits from being reinterpreted as a whole-file addition and overstating changed-line or call-reference evidence. diff --git a/dist/selection-workspace.d.ts.map b/dist/selection-workspace.d.ts.map index d907578..a86b5f5 100644 --- a/dist/selection-workspace.d.ts.map +++ b/dist/selection-workspace.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"selection-workspace.d.ts","sourceRoot":"","sources":["../src/selection-workspace.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AA2IhD,MAAM,WAAW,yBAAyB;IACxC,oBAAoB,CAAC,EAAE,MAAM,EAAE,CAAC;IAChC,yBAAyB,CAAC,EAAE,OAAO,CAAC;CACrC;AAED;;;;;GAKG;AACH,wBAAsB,+BAA+B,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,aAAa,EAAE,OAAO,GAAE,yBAA8B,GAAG,OAAO,CAAC,IAAI,CAAC,CAiCpJ"} \ No newline at end of file +{"version":3,"file":"selection-workspace.d.ts","sourceRoot":"","sources":["../src/selection-workspace.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AA4IhD,MAAM,WAAW,yBAAyB;IACxC,oBAAoB,CAAC,EAAE,MAAM,EAAE,CAAC;IAChC,yBAAyB,CAAC,EAAE,OAAO,CAAC;CACrC;AAED;;;;;GAKG;AACH,wBAAsB,+BAA+B,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,aAAa,EAAE,OAAO,GAAE,yBAA8B,GAAG,OAAO,CAAC,IAAI,CAAC,CAiCpJ"} \ No newline at end of file diff --git a/dist/selection-workspace.js b/dist/selection-workspace.js index cfd413a..0ffd8f1 100644 --- a/dist/selection-workspace.js +++ b/dist/selection-workspace.js @@ -1,6 +1,7 @@ import path from "node:path"; import { diffTargetCommit, GitError, gitNullDevice, listUntrackedFiles, resolveRevisionCommit } from "./git.js"; import { runProcess, safeExecutablePath } from "./process.js"; +import { normalizeRepoPath } from "./util.js"; const ROOT_DISCOVERY_METADATA = new Set([ "package.json", "tsconfig.json", @@ -108,7 +109,7 @@ async function ignoredFiles(root, pathspecs, exclusions) { const message = result.stderr.trim() || result.error || `git ls-files exited with ${String(result.exitCode)}`; throw new GitError(`Could not inspect ignored immutable-workspace inputs: ${message}`); } - return [...new Set(result.stdout.split("\0").filter(Boolean).map((file) => file.replaceAll("\\", "/")))].sort(); + return [...new Set(result.stdout.split("\0").filter(Boolean).map(normalizeRepoPath))].sort(); } function isPythonDiscoveryPath(repoPath) { const segments = repoPath.split("/"); @@ -125,7 +126,7 @@ function repoLocalDataArtifact(root, artifact) { const relative = path.relative(root, absolute); if (!relative || relative.startsWith("..") || path.isAbsolute(relative)) return null; - const normalized = relative.replaceAll("\\", "/"); + const normalized = normalizeRepoPath(relative); return isDiscoverySensitivePath(normalized) ? null : normalized; } function boundedDetail(files) { diff --git a/dist/selection-workspace.js.map b/dist/selection-workspace.js.map index 8650b0a..a4a21bf 100644 --- a/dist/selection-workspace.js.map +++ b/dist/selection-workspace.js.map @@ -1 +1 @@ -{"version":3,"file":"selection-workspace.js","sourceRoot":"","sources":["../src/selection-workspace.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"selection-workspace.js","sourceRoot":"","sources":["../src/selection-workspace.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/src/selection-workspace.ts b/src/selection-workspace.ts index 145b443..0fe75bb 100644 --- a/src/selection-workspace.ts +++ b/src/selection-workspace.ts @@ -2,6 +2,7 @@ import path from "node:path"; import { diffTargetCommit, GitError, gitNullDevice, listUntrackedFiles, resolveRevisionCommit } from "./git.js"; import { runProcess, safeExecutablePath, type ProcessResult } from "./process.js"; import type { DiffSelection } from "./types.js"; +import { normalizeRepoPath } from "./util.js"; const ROOT_DISCOVERY_METADATA = new Set([ "package.json", @@ -112,7 +113,7 @@ async function ignoredFiles(root: string, pathspecs: string[], exclusions: strin const message = result.stderr.trim() || result.error || `git ls-files exited with ${String(result.exitCode)}`; throw new GitError(`Could not inspect ignored immutable-workspace inputs: ${message}`); } - return [...new Set(result.stdout.split("\0").filter(Boolean).map((file) => file.replaceAll("\\", "/")))].sort(); + return [...new Set(result.stdout.split("\0").filter(Boolean).map(normalizeRepoPath))].sort(); } function isPythonDiscoveryPath(repoPath: string): boolean { @@ -130,7 +131,7 @@ function repoLocalDataArtifact(root: string, artifact: string): string | null { const absolute = path.isAbsolute(artifact) ? path.normalize(artifact) : path.resolve(root, artifact); const relative = path.relative(root, absolute); if (!relative || relative.startsWith("..") || path.isAbsolute(relative)) return null; - const normalized = relative.replaceAll("\\", "/"); + const normalized = normalizeRepoPath(relative); return isDiscoverySensitivePath(normalized) ? null : normalized; } diff --git a/tests/selection-workspace.test.ts b/tests/selection-workspace.test.ts index eefd04d..6598b2a 100644 --- a/tests/selection-workspace.test.ts +++ b/tests/selection-workspace.test.ts @@ -94,6 +94,62 @@ test("ignored runtime-only inputs are allowed statically but rejected before rep ); }); +test("explicit POSIX data artifacts preserve literal backslashes in their own identity", { skip: process.platform === "win32" }, async (context) => { + const root = await initializeRepository({ + ".gitignore": "coverage*\n", + "src/value.js": "export const value = 1;\n", + }); + context.after(() => rm(root, { recursive: true, force: true })); + const base = git(root, "rev-parse", "HEAD").trim(); + const target = await commitChange(root, "export const value = 2;\n", "selected change"); + await writeFiles(root, { + "coverage\\proof.lcov": "TN:\nSF:src/value.js\nDA:1,1\nend_of_record\n", + }); + + const report = await analyzeRepository({ + repo: root, + base, + runChecks: true, + coverageLcov: "coverage\\proof.lcov", + coverageCommit: target, + }); + assert.equal(report.coverage?.accepted, true); + assert.equal(report.coverage?.artifact, "coverage\\proof.lcov"); +}); + +test("ignored POSIX paths preserve literal backslashes instead of aliasing allowed artifacts", { skip: process.platform === "win32" }, async (context) => { + const root = await initializeRepository({ + ".gitignore": "coverage*\n", + "package.json": JSON.stringify({ name: "ignored-path-identity", private: true, type: "module", scripts: { test: "node --test" } }, null, 2), + "src/value.js": "export const value = 1;\n", + "test/value.test.js": "import test from 'node:test'; import assert from 'node:assert/strict'; import { readFileSync } from 'node:fs'; import { value } from '../src/value.js'; test('value', () => { assert.equal(value, 2); assert.equal(readFileSync('coverage\\\\proof.lcov', 'utf8').trim(), 'allow'); });\n", + }); + context.after(() => rm(root, { recursive: true, force: true })); + const base = git(root, "rev-parse", "HEAD").trim(); + const target = await commitChange(root, "export const value = 2;\n", "selected change"); + await writeFiles(root, { + "coverage/proof.lcov": "TN:\nSF:src/value.js\nDA:1,1\nend_of_record\n", + "coverage\\proof.lcov": "allow\n", + }); + + await assert.rejects( + analyzeRepository({ + repo: root, + base, + runChecks: true, + coverageLcov: "coverage/proof.lcov", + coverageCommit: target, + timeoutMs: 20_000, + }), + (error: unknown) => { + assert.ok(error instanceof Error); + assert.match(error.message, /ignored filesystem input.*visible to repository execution/); + assert.ok(error.message.includes("coverage\\proof.lcov")); + return true; + }, + ); +}); + test("ignored dependency directories remain allowed as execution environment", async (context) => { const root = await initializeRepository({ ".gitignore": "node_modules/\n",