feat(content-guards): add secret-guard PreToolUse hook#338
Closed
JacobPEvans-personal wants to merge 1 commit into
Closed
feat(content-guards): add secret-guard PreToolUse hook#338JacobPEvans-personal wants to merge 1 commit into
JacobPEvans-personal wants to merge 1 commit into
Conversation
Block hardcoded sensitive homelab values (real internal IPs, the real domain, node/pool names, account IDs) from being written into a repo. Fires on Write/Edit/MultiEdit/NotebookEdit and inspects the content field (content, new_string, edits[].new_string, new_source). Two detection prongs: - Literal: a private newline-separated POSIX-ERE denylist (SENSITIVE_DENYLIST) read from the macOS auto-readable keychain. Never committed; referenced by name only. - Structural (value-free): RFC1918 IP literals (10./192.168./172.16-31.), allowlisting fake test values (RFC2544 198.18/198.19, example.invalid). A real-domain shape is supported but OFF by default (fires on every write; a broad TLD match would be hostile) and opt-in via SECRET_GUARD_DOMAIN_REGEX. Fail-open: missing/empty denylist, unreadable keychain, or any internal error allows the write with a one-line stderr warning. The deny reason names the matched category, never the matched value, so secrets are not re-surfaced. Mirrors the established deny protocol (JSON hookSpecificOutput/deny on stdout, exit 0) from webfetch-guard.py and main-branch-guard.py. Adds self-contained python tests and a bats suite using FAKE values only; CI runs both. Assisted-by: Claude:claude-opus-4-8[1m]
Member
Author
|
Closing per maintainer: NO custom scripts. The secret-guard PreToolUse hook was a bespoke Python script — rejected. Secret scanning will be gitleaks-only (no wrappers). |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Layer 1 of the multi-layer sensitive-value prevention system: a
secret-guardPreToolUse hook in the
content-guardsplugin that blocks hardcoded sensitivehomelab values from being written into a repo. It fires on
Write|Edit|MultiEdit|NotebookEditand inspects the content field(
content,new_string,edits[].new_string,new_source).Detection prongs
(
SENSITIVE_DENYLIST) read from the macOS auto-readable keychain viasecurity find-generic-password -s SENSITIVE_DENYLIST -w. Holds the exactreal domain, node/pool names, and account ID. Never committed; referenced by
name only.
(
10./192.168./172.16-31.), allowlisting fake test values (RFC2544198.18/198.19,example.invalid). A real-domain shape is supported butoff by default (the hook fires on every write, so a broad TLD match would
block ordinary content mentioning
github.cometc. and be hostile) — opt inper repo via
SECRET_GUARD_DOMAIN_REGEX. The real domain is caught by theliteral prong instead.
Behavior
webfetch-guard.py/main-branch-guard.py— JSONhookSpecificOutput/permissionDecision: denyon stdout, exit 0. The reasonnames the matched category, never the matched value, so a secret is not
re-surfaced.
internal error allows the write with a one-line stderr warning. Fresh clones
and external contributors without the keychain entry are never blocked; the
structural prong still runs when the literal denylist is unavailable.
Files
content-guards/scripts/secret-guard.py(new, executable)content-guards/scripts/test_secret_guard.py(new, executable) — self-containedtests/content-guards/secret-guard/secret-guard.bats(new) — CI bats suitecontent-guards/hooks/hooks.json— register the PreToolUse matchercontent-guards/README.md,content-guards/ARCHITECTURE.md— docscontent-guards/.claude-plugin/plugin.json— version 1.7.0 -> 1.8.0, keywordsTesting (FAKE values only)
Tests use only fake values: RFC1918 IP shapes with non-homelab octets,
RFC2544
198.18/198.19(allowlisted),example.invalid(allowlisted). CIruns both the bats suite and the python test. Coverage: structural IP-shape
deny, RFC2544/example.invalid allowlisting, clean-content allow, Edit/MultiEdit/
NotebookEdit field extraction, domain prong off-by-default + opt-in, fail-open
on absent keychain, deny-reason omits the matched value, and (on macOS only) a
seeded TEST-keychain literal-denylist deny that cleans up its own entry.
Docs mirroring (for the lead)
Per repo-boundaries, mirror into
JacobPEvans/docsdocs/ai-development/claude-code-plugins.mdx: content-guards now ships asecret-guard PreToolUse hook (matcher
Write|Edit|MultiEdit|NotebookEdit)— keychain
SENSITIVE_DENYLISTliteral prong + value-free RFC1918 structuralprong, fail-open, with
SECRET_GUARD_DOMAIN_REGEXopt-in. Plugin version 1.8.0.🤖 Generated with Claude Code