add pre-commit-secret-scan hook (blocks commits containing real credentials; install via core.hooksPath)

This commit is contained in:
2026-08-04 08:45:02 +10:00
parent 021d4cc2d6
commit b3247fa75c

View File

@@ -0,0 +1,45 @@
#!/bin/sh
# pre-commit-secret-scan — blocks commits that would add real credentials.
#
# Deployed via core.hooksPath (e.g. ~/.config/git/hooks/pre-commit) so it runs
# for EVERY repository on the machine. Fails OPEN (never blocks) if git itself
# is unavailable. Override only when you're sure: SKIP_SECRET_SCAN=1 git commit
#
# Pattern set covers the key formats used in this house: OpenAI sk-proj-,
# OpenRouter sk-or-v1-, GitHub ghp_, Tavily tvly-, Gemini AIza*, ntfy-style
# AQ.Ab*, JWTs (eyJ...), generic sk-... and Bearer tokens, private key blocks.
# Lines that only REFERENCE keys (nix builtins.getEnv, literal '...'
# placeholders) are ignored.
[ -n "$SKIP_SECRET_SCAN" ] && exit 0
# fail-open: not a git repo, or git unavailable
git rev-parse --git-dir >/dev/null 2>&1 || exit 0
# nothing staged -> nothing to check
[ -n "$(git diff --cached --name-only 2>/dev/null)" ] || exit 0
hits=$(git diff --cached -U0 --no-color 2>/dev/null | awk '
/^diff --git/ { f=$3; sub(/^a\//,"",f) }
/^\+/ && $0 !~ /^\+\+\+/ {
l = substr($0, 2)
if (l ~ /getEnv|\.\.\./) next
if (l ~ /sk-proj-[A-Za-z0-9._-]{20,}|sk-or-v1-[A-Za-z0-9._-]{20,}|ghp_[A-Za-z0-9]{20,}|tvly-[A-Za-z0-9]{20,}|AIza[A-Za-z0-9_-]{30,}|AQ\.Ab[A-Za-z0-9._-]{20,}|eyJ[A-Za-z0-9._-]{30,}|sk-[A-Za-z0-9]{25,}|Bearer [A-Za-z0-9._-]{25,}|BEGIN [A-Z ]*PRIVATE KEY/)
print f ": " l
}')
[ -z "$hits" ] && exit 0
echo "⛔ pre-commit secret scan BLOCKED — possible credentials in staged changes:" >&2
echo "$hits" | sed -E '
s/(sk-proj-[A-Za-z0-9._-]{6})[A-Za-z0-9._-]+/\1…/g
s/(sk-or-v1-[A-Za-z0-9._-]{6})[A-Za-z0-9._-]+/\1…/g
s/(ghp_[A-Za-z0-9]{4})[A-Za-z0-9]+/\1…/g
s/(tvly-[A-Za-z0-9]{4})[A-Za-z0-9]+/\1…/g
s/(AIza[A-Za-z0-9_-]{4})[A-Za-z0-9_-]+/\1…/g
s/(AQ\.Ab[A-Za-z0-9._-]{4})[A-Za-z0-9._-]+/\1…/g
s/(eyJ[A-Za-z0-9._-]{8})[A-Za-z0-9._-]+/\1…/g
s/(sk-[A-Za-z0-9]{6})[A-Za-z0-9]+/\1…/g
s/(Bearer [A-Za-z0-9._-]{6})[A-Za-z0-9._-]+/\1…/g' >&2
echo "→ Remove the secret and re-commit. If it's a false positive: SKIP_SECRET_SCAN=1 git commit" >&2
exit 1