Skip to content

feat(security): M14.10 secret_commit — a credential file staged, or a token in the staged diff - #216

Merged
ra3orblade merged 1 commit into
mainfrom
feat/m14-10-secret
Oct 24, 2026
Merged

ra3orblade merged 1 commit into
mainfrom
feat/m14-10-secret

Conversation

@ra3orblade

Copy link
Copy Markdown
Owner

The last of the three tasks added after the review, and the one guard the others could not express: a secret about to enter git history.

What it does

  • secret_commit (ask by default) fires on git add .env, a git commit or git rm --cached naming a credential file, and on a git commit whose staged diff adds a token. The daemon reads git diff --cached -U0 lazily, only when the command commits and the family is on, and secretTokensIn matches the added lines against ten vendor-prefixed shapes (private key block, AWS, GitHub, Anthropic, OpenAI, Slack, GitLab, Google, Stripe, npm). The reason names the shape, never the value, and says what to do: unstage, move the value out, rotate if it was ever pushed.
  • Quoted strings are dropped before the name match, so a commit message that mentions .env is not a leak. Without a reader (the offline shim, a non-repository) the family fails open on the diff side and still matches names.
  • [rules] secret_commit = "ask"; the family is counted on Security › Activity and named in the session context.

Verification: typecheck · lint · test (1083 pass) · smoke · docs:check. The daemon test runs on a real temporary repository: git add .env asks, a commit whose staged file adds an AWS key asks naming the shape, and the same commit after unstaging is allowed.

🤖 Generated with Claude Code

… token in the staged diff

guards.ts: secretCommit — a `git add` / `stage` / `commit` / `rm --cached`
segment in command position naming a file on the secrets list (quoted
strings dropped first, so a commit message that mentions .env is not a
leak), and, when the command commits, the staged diff read lazily through a
reader and matched on its added lines by secretTokensIn: ten vendor-prefixed
shapes (a private key block, AWS, GitHub, Anthropic, OpenAI, Slack, GitLab,
Google, Stripe, npm). The shape is named, never the value.

rules.ts: family `secret_commit` (ask by default), familyHitsBash takes the
reader as a fifth optional argument and guardBash carries it as
ctx.stagedDiff; without one the family only matches names, so the offline
shim fails open. config: [rules] secret_commit = "ask". The session context
names the mode.

daemon: git.ts stagedDiff (git diff --cached -U0, no colour, no external
diff; null outside a repository) and evaluateTool hands it in lazily — the
diff is read only when the command commits and the family is on. The
Activity scan counts the family from the command text.

Tests: guards (names, quoted messages, lazy reads, every token shape),
rules (ask / deny / off / no reader), daemon on a real temporary repository
(git add .env asks; a commit whose staged file adds an AWS key asks naming
the shape; the same commit after unstaging is allowed).

Docs: roadmap M14.10 flipped; config reference; the rules guide; CLAUDE.md.

Verified: typecheck · lint · test (1083 pass) · smoke · docs:check.

Co-Authored-By: Claude <noreply@anthropic.com>
@ra3orblade
ra3orblade merged commit cae5d77 into main Oct 24, 2026
2 checks passed
@ra3orblade
ra3orblade deleted the feat/m14-10-secret branch October 24, 2026 10:46
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.

1 participant