Skip to main content

max / shop

Add shared pre-commit hook: gitleaks secret scan + rustfmt gate Adopts the scripts/githooks convention (core.hooksPath) used across the other ~/Code repos, with the gitleaks guardrail from the start. Task: infra 97ffeda0
Co-Authored-By
Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Author: Max Johnson <me@maxj.phd> · 2026-07-25 14:48 UTC
Signed with PGP, not checked
Commit: 99074a49cc4760bff1f593b1a09d5c64c77494af
Parent: 3c5b22e
1 file changed, +85 insertions, -0 deletions
@@ -1,0 +1,85 @@
1 + #!/bin/bash
2 + # pre-commit: secret-scan gate, then rustfmt gate.
3 + #
4 + # Activate in a fresh clone (one-time):
5 + # git config core.hooksPath scripts/githooks
6 + #
7 + # Bypass for a work-in-progress commit: git commit --no-verify
8 + set -euo pipefail
9 +
10 + ROOT="$(git rev-parse --show-toplevel)"
11 + cd "$ROOT"
12 +
13 + # ---------------------------------------------------------------------------
14 + # 1. Secret scan (gitleaks). The independent guardrail: blocks a commit whose
15 + # staged changes contain a secret, regardless of whether a human judged the
16 + # value "safe". Shared ruleset lives at ~/Code/.gitleaks.toml.
17 + #
18 + # Degrades gracefully: if gitleaks is not installed we warn and continue,
19 + # so a contributor without the tool is not blocked (the astra pre-receive
20 + # hook is the backstop that always runs).
21 + # ---------------------------------------------------------------------------
22 + if command -v gitleaks >/dev/null 2>&1; then
23 + # Prefer a repo-local config, then the shared one, else gitleaks defaults.
24 + GL_CFG=""
25 + if [ -f "$ROOT/.gitleaks.toml" ]; then
26 + GL_CFG="$ROOT/.gitleaks.toml"
27 + elif [ -f "$HOME/Code/.gitleaks.toml" ]; then
28 + GL_CFG="$HOME/Code/.gitleaks.toml"
29 + fi
30 + gl_args=(git --staged --no-banner --redact)
31 + [ -n "$GL_CFG" ] && gl_args+=(-c "$GL_CFG")
32 + if ! gitleaks "${gl_args[@]}"; then
33 + echo "pre-commit: gitleaks found a secret in the staged changes."
34 + echo "pre-commit: remove it (or add an allowlist entry if it is a false"
35 + echo " positive), then restage. Bypass: git commit --no-verify."
36 + exit 1
37 + fi
38 + echo "pre-commit: gitleaks clean."
39 + else
40 + echo "pre-commit: gitleaks not installed; skipping the secret scan."
41 + echo " install it to get the local guardrail (astra still gates on push)."
42 + fi
43 +
44 + # ---------------------------------------------------------------------------
45 + # 2. rustfmt gate: blocks a commit whose staged Rust files are not formatted.
46 + # Only crates with staged .rs changes are checked, so the hook stays fast.
47 + # ---------------------------------------------------------------------------
48 + SKIP_PATHS="${SKIP_PATHS:-}"
49 +
50 + staged="$(git diff --cached --name-only --diff-filter=ACMR -- '*.rs')"
51 + if [ -n "$SKIP_PATHS" ]; then
52 + staged="$(printf '%s\n' "$staged" | grep -Ev "$SKIP_PATHS" || true)"
53 + fi
54 + [ -n "$staged" ] || exit 0
55 +
56 + crates=""
57 + while IFS= read -r f; do
58 + [ -n "$f" ] || continue
59 + d="$(dirname "$f")"
60 + while [ "$d" != "." ] && [ ! -f "$d/Cargo.toml" ]; do
61 + d="$(dirname "$d")"
62 + done
63 + [ -f "$d/Cargo.toml" ] || continue
64 + crates="$crates$d"$'\n'
65 + done <<< "$staged"
66 +
67 + crates="$(printf '%s' "$crates" | sort -u)"
68 + [ -n "$crates" ] || exit 0
69 +
70 + failed=0
71 + while IFS= read -r c; do
72 + [ -n "$c" ] || continue
73 + if ! (cd "$c" && cargo fmt --check >/dev/null 2>&1); then
74 + echo "pre-commit: rustfmt gate failed in $c"
75 + failed=1
76 + fi
77 + done <<< "$crates"
78 +
79 + if [ "$failed" -ne 0 ]; then
80 + echo "pre-commit: run 'cargo fmt' in the crates above, then restage."
81 + echo "pre-commit: commit aborted (use --no-verify to bypass)."
82 + exit 1
83 + fi
84 +
85 + echo "pre-commit: rustfmt gate clean."