fix(verify-no-secrets): resolve repo root via git, allow scaffolding under secrets/
Two defects found by testing the guard against itself: 1. When invoked through the .git/hooks/pre-commit symlink, deriving the repo root from dirname(BASH_SOURCE)/.. resolved to .git/ instead of the work tree, so the hook scanned nothing and never blocked. Use 'git rev-parse --show-toplevel' instead. 2. The blanket secrets/ rule rejected secrets/.gitkeep. Replaced with an explicit allowlist: .gitkeep, README.md, *.example, *.template. Verified: a staged file containing a Telegram bot token now aborts the commit and leaves HEAD unchanged.
This commit is contained in:
@@ -16,7 +16,13 @@
|
||||
# ---------------------------------------------------------------------------
|
||||
set -uo pipefail
|
||||
|
||||
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
# Resolve the repository root via git, not via BASH_SOURCE: when this script is
|
||||
# invoked through the .git/hooks/pre-commit symlink, dirname(BASH_SOURCE)/..
|
||||
# resolves to .git/ rather than the work tree.
|
||||
REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null)" || {
|
||||
echo "verify-no-secrets: not inside a git work tree" >&2
|
||||
exit 1
|
||||
}
|
||||
cd "$REPO_ROOT" || exit 1
|
||||
|
||||
MODE="${1:-staged}"
|
||||
@@ -40,14 +46,21 @@ fail() {
|
||||
}
|
||||
|
||||
# --- Rule 1: filenames that must never be committed ------------------------
|
||||
FORBIDDEN_NAMES='(^|/)(models\.json|auth\.json|trust\.json|models-store\.json)$|(^|/)\.env$|\.env\.[^/]*$|(^|/)id_(ed25519|rsa)|\.(pem|p12)$|\.rendered(\..*)?$|(^|/)secrets/(?!.*\.(example|template)$)'
|
||||
FORBIDDEN_NAMES='(^|/)(models\.json|auth\.json|trust\.json|models-store\.json)$|(^|/)\.env$|\.env\.[^/]*$|(^|/)id_(ed25519|rsa)|\.(pem|p12)$|\.rendered(\..*)?$'
|
||||
# Inside secrets/ only documentation and placeholder scaffolding may be tracked.
|
||||
SECRETS_ALLOWED='(^|/)secrets/(\.gitkeep|README\.md|.*\.(example|template))$'
|
||||
for f in "${FILES[@]}"; do
|
||||
# .env.example / .env.template are allowed
|
||||
# Templates and examples are the intended way to track credential-shaped files.
|
||||
case "$f" in
|
||||
*.env.example|*.env.template|*.example|*.template) continue ;;
|
||||
esac
|
||||
if printf '%s' "$f" | grep -qP "$FORBIDDEN_NAMES"; then
|
||||
fail "$f" "filename is on the never-commit list"
|
||||
continue
|
||||
fi
|
||||
if printf '%s' "$f" | grep -qP '(^|/)secrets/' \
|
||||
&& ! printf '%s' "$f" | grep -qP "$SECRETS_ALLOWED"; then
|
||||
fail "$f" "files under secrets/ may only be .gitkeep, README.md, *.example or *.template"
|
||||
fi
|
||||
done
|
||||
|
||||
|
||||
Reference in New Issue
Block a user