Skip to content

secret-guard: a commit scans only the untracked files its git add names - #178

Merged
hamzafer merged 4 commits into
hamzafer:mainfrom
padschneider:pad/secret-guard-add-paths
Nov 14, 2026
Merged

hamzafer merged 4 commits into
hamzafer:mainfrom
padschneider:pad/secret-guard-add-paths

Conversation

@padschneider

Copy link
Copy Markdown
Contributor

What happened

In a repo with one big untracked file lying around (here a 2.3 MB esbuild meta report), every git add <files> && git commit asked:

This commit is too big to check whole: secret-guard read part of it and found no keys there.

untracked() lists every untracked file git doesn't ignore, whatever the git add named, and any file over 1 MB marks the scan as cut. So the ask came up on every commit, even though the commit never included that file.

Change

  • New addPaths(command) reads the pathspecs of each git add in the command.
  • untracked() passes them to git ls-files --others -- <paths>, so only files the add stages are read.
  • Anything it can't read safely still scans every untracked file, as before: ., -A/--all, -u, globs, $vars.
  • Version 0.1.1 → 0.1.2 (plugin.json, marketplace.json, site page).

Tests

  • New tests: a big untracked file outside the add is skipped, git add . still asks, and addPaths cases are covered. The mock ls-files now honours pathspecs.
  • I haven't run claude plugin test or the repo tests on my machine. Please let CI check.

🤖 Generated with Claude Code

`git add a.ts && git commit` read every untracked file git doesn't ignore. One
big untracked file the commit leaves out (a 2.3 MB build report) made every such
commit ask "too big to check whole". Now the untracked scan takes the add's
pathspecs; `git add .`, `-A`, `-u`, globs and `$vars` still read every untracked file.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@hamzafer hamzafer left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @padschneider, skipping big build files on a narrow git add is a nice win. The catch is that once the scan only covers the paths we parse, any path we parse wrong is a file that gets committed unscanned. A few cases that slip through today:

  • Escaped spaces: git add config\ prod.env && git commit splits into config\ and prod.env, so the real file is never scanned.
  • --pathspec-from-file / --pathspec-file-nul: git add a.ts --pathspec-from-file=l.txt returns ["a.ts"], and the files in l.txt are skipped (the space form also treats l.txt as a path).
  • The add's own -C: git -C sub add x.env && git commit yields x.env, but ls-files runs in the commit's cwd, so sub/x.env is missed.
  • Brace expansion, ~, line continuation: git add .env{,.local}, git add ~/x, and a \ line break before the next path all drop files.
  • One bad pathspec empties the scan: if any path is outside the repo or in a submodule, ls-files exits 128 and untracked() returns '', so no untracked file is scanned at all.

Suggested shape: make addPaths fail closed. Narrow only when every word after add is a plain relative path (no \ { } ~ : or $, no options outside a small known-safe set, no -C on the add, no non-leading cd), and fall back to the full untracked scan whenever ls-files exits non-zero. Tests for the cases above would lock it in.

Small docs note: docs/mods.md and the site page still say a commit scans the new files whenever the command runs git add, so they'll need a tweak to match.

…is plain

Review follow-up. addPaths now fails closed: it narrows only when each word
after `add` is a plain relative path or a known-safe option (-v, -f, -N), the
add has no global options of its own, nothing comes before `git` in its step,
and no cd moves the shell after the start. Escaped spaces, braces, ~, line
continuations, pathspec magic, --pathspec-from-file, redirections, -C on the
add and a commit's own -C all scan every untracked file, as before. A pathspec
git refuses (ls-files exits non-zero) falls back to the full list instead of
none. Tests cover each case; docs and site page say what's narrowed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@padschneider

Copy link
Copy Markdown
Contributor Author

Thanks for the careful review. All points are addressed in 94462aa:

  • addPaths fails closed. It narrows only when every word after add is a plain relative path or a known-safe option (-v, -f, -N). Otherwise it falls back to the full untracked scan. That covers \ (escaped spaces and line continuations), { } ~ : $ and globs, redirections, --pathspec-from-file / --pathspec-file-nul and any other option, global options on the add (git -C sub add, --git-dir), anything before git in its step (GIT_DIR=… git add, xargs git add), and any cd other than a leading cd x && (including (cd sub && git add …)).
  • A commit with its own -C also scans every untracked file there, since its cwd differs from the add's.
  • ls-files exiting non-zero with pathspecs (outside the repo, in a submodule) now reruns without them, instead of scanning nothing.
  • Tests cover each case from your list, plus the -C commit and the exit-128 fallback.
  • Docs: docs/mods.md and the site page now say which new files a commit reads.

claude plugin test mods/secret-guard passes (37), and so do node --test test/*.test.mjs (217) and claude plugin validate.

…s plain git

addPaths now narrows only when the command is an optional leading cd plus
git add, commit, push and status. A hidden add beside a plain one (git stage,
bash -c, eval, a heredoc, "git" add, git -c alias), a cd the parse missed
({ cd x; }, command cd) and a path glued from quoted and bare parts all scan
every untracked file again. A quoted-heredoc commit message still narrows.

@hamzafer hamzafer left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @padschneider, nice work on the fail-closed parse. I pushed one follow-up commit (07e13c0) on top: addPaths now narrows only when the whole command is a leading cd plus plain git add/commit/push/status steps, so a hidden add next to a plain one (git stage, bash -c, eval, "git" add), a missed cd ({ cd x; }, command cd, cd -), a path glued from quoted and bare parts, and a commit-message heredoc with an early EOF line all scan every untracked file again. A quoted-heredoc commit message still narrows. Tests cover each case.

@hamzafer
hamzafer merged commit 8ed7ab7 into hamzafer:main Nov 14, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants