#!/usr/bin/env bash set -euo pipefail # ECC Codex Git Hook: pre-commit # Blocks commits that add high-signal secrets. if [[ "${ECC_SKIP_GIT_HOOKS:-0}" == "1" || "${ECC_SKIP_PRECOMMIT:-0}" == "1" ]]; then printf '[ECC pre-commit] WARNING: hook bypassed via env (ECC_SKIP_*=1)\n' >&2 exit 0 fi # NOTE: file-based disables (.ecc-hooks-disable) were removed — a malicious # repo could ship that file and silently turn off secret scanning exactly # where it is most needed. Use the env bypass above (audible warning) instead. if ! git rev-parse --is-inside-work-tree >/dev/null 2>&1; then exit 0 fi staged_files="$(git diff --cached --name-only --diff-filter=ACMR || true)" if [[ -z "$staged_files" ]]; then exit 0 fi has_findings=0 scan_added_lines() { local file="$1" local name="$2" local regex="$3" local added_lines local hits added_lines="$(git diff --cached -U0 -- "$file" | awk '/^\+\+\+ /{next} /^\+/{print substr($0,2)}')" if [[ -z "$added_lines" ]]; then return 0 fi if hits="$(printf '%s\n' "$added_lines" | rg -n --pcre2 "$regex" 2>/dev/null)"; then printf '\n[ECC pre-commit] Potential secret detected (%s) in %s\n' "$name" "$file" >&2 printf '%s\n' "$hits" | head -n 3 >&2 has_findings=1 fi } while IFS= read -r file; do [[ -z "$file" ]] && continue case "$file" in *.png|*.jpg|*.jpeg|*.gif|*.svg|*.pdf|*.zip|*.gz|*.lock|pnpm-lock.yaml|package-lock.json|yarn.lock|bun.lockb) continue ;; esac scan_added_lines "$file" "OpenAI key" 'sk-[A-Za-z0-9]{20,}' scan_added_lines "$file" "GitHub classic token" 'ghp_[A-Za-z0-9]{36}' scan_added_lines "$file" "GitHub fine-grained token" 'github_pat_[A-Za-z0-9_]{20,}' scan_added_lines "$file" "AWS access key" 'AKIA[0-9A-Z]{16}' scan_added_lines "$file" "private key block" '-----BEGIN (RSA|EC|OPENSSH|DSA|PRIVATE) KEY-----' scan_added_lines "$file" "generic credential assignment" "(?i)\\b(api[_-]?key|secret|password|token)\\b\\s*[:=]\\s*['\\\"][^'\\\"]{12,}['\\\"]" done <<< "$staged_files" if [[ "$has_findings" -eq 1 ]]; then cat >&2 <<'EOF' [ECC pre-commit] Commit blocked to prevent secret leakage. Fix: 1) Remove secrets from staged changes. 2) Move secrets to env vars or secret manager. 3) Re-stage and commit again. Temporary bypass (not recommended): ECC_SKIP_PRECOMMIT=1 git commit ... EOF exit 1 fi exit 0