From 45caf760a4a8b2788316c9614c7d5bfac0a301ca Mon Sep 17 00:00:00 2001 From: Andrei Hasna Date: Fri, 7 Aug 2026 21:13:52 +0300 Subject: [PATCH] fix(cli): treat staged paths literally Agent: vespasian --- src/cli/commands/review.test.ts | 34 +++++++++++++++++++++++++++++++++ src/cli/commands/review.ts | 11 ++++++++++- 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/src/cli/commands/review.test.ts b/src/cli/commands/review.test.ts index 022f65d..adb0398 100644 --- a/src/cli/commands/review.test.ts +++ b/src/cli/commands/review.test.ts @@ -100,6 +100,40 @@ describe("review staged-diff boundary", () => { expect(sourceFile.stdout).toContain("CRITICAL fixture.ts:1"); }); + test("treats staged filenames as literal git pathspecs", () => { + const repo = createRepo("literal-pathspec"); + const fileName = ":(literal)fixture.ts"; + writeFileSync(join(repo, fileName), `const token = "${syntheticGitHubToken}";\n`); + execFileSync("git", ["--literal-pathspecs", "add", "--", fileName], { cwd: repo }); + + const result = runReview(repo); + expect(result.status).toBe(0); + expect(result.stderr).toBe(""); + expect(result.stdout).toContain(`CRITICAL ${fileName}:1`); + expect(result.stdout).not.toContain("No security issues found in staged changes."); + + const normalRepo = createRepo("normal-pathspec-control"); + writeFileSync( + join(normalRepo, "fixture.ts"), + `const token = "${syntheticGitHubToken}";\n`, + ); + execFileSync("git", ["add", "--", "fixture.ts"], { cwd: normalRepo }); + + const normal = runReview(normalRepo); + expect(normal.status).toBe(0); + expect(normal.stderr).toBe(""); + expect(normal.stdout).toContain("CRITICAL fixture.ts:1"); + + const safeRepo = createRepo("safe-pathspec-control"); + writeFileSync(join(safeRepo, "fixture.ts"), "const safe = true;\n"); + execFileSync("git", ["add", "--", "fixture.ts"], { cwd: safeRepo }); + + const safe = runReview(safeRepo); + expect(safe.status).toBe(0); + expect(safe.stderr).toBe(""); + expect(safe.stdout).toContain("No security issues found in staged changes."); + }); + test("scans the staged index content rather than later unstaged edits", () => { const repo = createRepo("index-content"); writeFileSync(join(repo, "fixture.ts"), "const safe = true;\n"); diff --git a/src/cli/commands/review.ts b/src/cli/commands/review.ts index 6cad9f5..fab4400 100644 --- a/src/cli/commands/review.ts +++ b/src/cli/commands/review.ts @@ -41,7 +41,16 @@ function safeStagedPath(filePath: string): string { function addedLinesForFile(cwd: string, filePath: string): Set { const diff = execFileSync( "git", - ["diff", "--cached", "--unified=0", "--no-color", "--no-ext-diff", "--", filePath], + [ + "--literal-pathspecs", + "diff", + "--cached", + "--unified=0", + "--no-color", + "--no-ext-diff", + "--", + filePath, + ], { cwd, encoding: "utf-8" }, ); const addedLines = new Set();