#!/usr/bin/env bash set -euo pipefail if ! git rev-parse --git-dir >/dev/null 2>&1; then echo "Not inside a git repository." exit 1 fi if ! command -v rg >/dev/null 2>&1; then echo "ripgrep (rg) is required for secret scanning." exit 1 fi staged_files=() while IFS= read -r file; do staged_files+=("$file") done < <(git diff --cached --name-only --diff-filter=ACMRTUXB) if [ "${#staged_files[@]}" -eq 0 ]; then exit 0 fi secret_pattern='AKIA[0-9A-Z]{16}|ASIA[0-9A-Z]{16}|ghp_[A-Za-z0-9]{36}|github_pat_[A-Za-z0-9_]{20,}|xox[baprs]-[A-Za-z0-9-]{10,}|AIza[0-9A-Za-z_-]{35}|-----BEGIN (RSA|OPENSSH|EC|DSA|PRIVATE) KEY-----|(?i)(password|passwd|pwd|secret|token|api[_-]?key|jwt_secret)\s*[:=]\s*["'"'"'][^"'"'"'\s]{8,}["'"'"']' allow_pattern='CHANGE_ME|REDACTED|PLACEHOLDER|EXAMPLE|example|<[^>]+>' found=0 for file in "${staged_files[@]}"; do case "$file" in dist/*|*.png|*.jpg|*.jpeg|*.gif|*.webp|*.pdf|*.zip|*.gz|*.exe|*.dll|*.so|*.dylib) continue ;; esac if ! content="$(git show ":$file" 2>/dev/null)"; then continue fi hits="$(printf '%s' "$content" | rg -n --no-heading -e "$secret_pattern" || true)" if [ -n "$hits" ]; then filtered="$(printf '%s\n' "$hits" | rg -v -e "$allow_pattern" || true)" if [ -n "$filtered" ]; then echo "Potential secret found in staged file: $file" printf '%s\n' "$filtered" found=1 fi fi done if [ "$found" -ne 0 ]; then echo echo "Commit blocked: remove or redact secrets before committing." exit 1 fi exit 0