#!/usr/bin/env bash # Secret scan over the commits about to be pushed. Opt in per clone with: # # git config core.hooksPath .githooks # # Self-contained on purpose: this repo has no Makefile, and a hook that # depends on one in a sibling repo breaks the moment the repo is cloned # anywhere else. set -euo pipefail cd "$(git rev-parse --show-toplevel)" # A non-login shell — which is what git gives a hook — skips /etc/profile.d # and never sees ~/.local/bin, where the gitleaks release tarball lands. # Without this the scan reports "not installed" on every push. [ -d "$HOME/.local/bin" ] && PATH="$HOME/.local/bin:$PATH" if ! command -v gitleaks >/dev/null 2>&1; then echo "FAIL secrets — gitleaks not installed, so this check would be a no-op pretending to pass." >&2 echo " https://github.com/gitleaks/gitleaks/releases → ~/.local/bin/gitleaks" >&2 exit 1 fi # Scan the outgoing range, not full history. History here carries findings # that are settled — test fixtures and vendored third-party code — and a gate # that fails on something unfixable gets bypassed within a week. What matters # is what is about to leave this machine. if upstream=$(git rev-parse --abbrev-ref --symbolic-full-name '@{u}' 2>/dev/null); then range="$upstream..HEAD" elif git rev-parse --verify --quiet origin/main >/dev/null; then range="origin/main..HEAD" else range="" fi if [ -z "$range" ]; then gitleaks dir . --redact --no-banner --exit-code 1 || { echo "FAIL secrets — gitleaks found a credential in the working tree." >&2; exit 1; } exit 0 fi [ -n "$(git log --oneline "$range" 2>/dev/null)" ] || exit 0 gitleaks git . --log-opts="$range" --redact --no-banner --exit-code 1 >/dev/null 2>&1 || { echo "FAIL secrets — gitleaks found a credential in the commits being pushed." >&2 echo " inspect (values redacted): gitleaks git . --log-opts=\"$range\" --redact" >&2 echo " then remove and rotate it, or suppress deliberately:" >&2 echo " inline '# gitleaks:allow '" >&2 echo " or add the fingerprint to .gitleaksignore WITH a reason" >&2 exit 1 } echo " ok secrets"