From d98a30598591c50acb2b6f0ce0c858fd9476dff3 Mon Sep 17 00:00:00 2001 From: Mathias Date: Fri, 28 Aug 2026 23:58:05 +0200 Subject: [PATCH] security(hooks): add local pre-commit gitleaks scan (infra#326) task check -> security:gitleaks was already CI-enforced here, but that catches a leak after the push, not before -- exactly the gap infra#39's prevention checklist called out ("gitleaks pre-commit hook in both infra and hyperguild"), true for infra but not this repo. Mirrors infra's own .githooks/pre-commit, minus the YAML/image-tag checks that are infra-manifest-specific and don't apply here. Verified functionally, not just wired: staged a real high-entropy fake key and confirmed `git commit` is blocked by the hook (RuleID=generic-api-key); staged a well-known documented-example AWS key (AKIAIOSFODNN7EXAMPLE) first and confirmed gitleaks correctly passes it (it's not a real leak, and gitleaks' own default rules know that) -- worth recording since a naive fixture check would have looked like detection was broken. Enable per clone: git config core.hooksPath .githooks --- .githooks/pre-commit | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100755 .githooks/pre-commit diff --git a/.githooks/pre-commit b/.githooks/pre-commit new file mode 100755 index 0000000..b1d485e --- /dev/null +++ b/.githooks/pre-commit @@ -0,0 +1,34 @@ +#!/usr/bin/env bash +# Pre-commit secret scan for the hyperguild repo. +# +# task check -> security:gitleaks enforces this in CI, but CI is after the +# push. This catches a staged secret before it ever leaves the machine -- +# the infra#39 rotation pass found exactly this class of leak (a printed +# credential, committed, archived into git) and there was no local gate to +# have caught it. Mirrors infra's own .githooks/pre-commit (infra#326). +# +# Enable once per clone: git config core.hooksPath .githooks +# Bypass if absolutely needed: git commit --no-verify + +set -euo pipefail + +GITLEAKS="$(command -v gitleaks || true)" +if [[ -z "$GITLEAKS" && -x "$(go env GOPATH 2>/dev/null)/bin/gitleaks" ]]; then + GITLEAKS="$(go env GOPATH)/bin/gitleaks" +fi + +if [[ -z "$GITLEAKS" ]]; then + echo "⚠ gitleaks not installed — skipping local secret scan (CI still enforces it)." + echo " Install: go install github.com/zricethezav/gitleaks/v8@latest" + exit 0 +fi + +echo "→ Scanning staged changes for secrets..." +if ! "$GITLEAKS" protect --staged --redact --config .gitleaks.toml >/dev/null 2>&1; then + echo " ✗ gitleaks found a secret in the staged changes." + echo " Review with: gitleaks protect --staged --redact --config .gitleaks.toml -v" + echo " If it is a false positive, allowlist it in .gitleaks.toml or add a" + echo " '# gitleaks:allow' comment. Do NOT --no-verify a real secret." + exit 1 +fi +echo " ✓ no staged secrets"