#!/usr/bin/env bash set -euo pipefail mode="${1:---staged}" repo_root="$(git rev-parse --show-toplevel)" cd "$repo_root" if [[ "$mode" != "--staged" && "$mode" != "--files" ]]; then echo "usage: $0 [--staged|--files ...]" >&2 exit 2 fi artifact_path_regex='(^|/)(docs/baselines/|baselines/|snapshots?/|exports?/|dumps?/|backups?/|diagnostics?/|artifacts?/|tmp/|temp/)|(^|/).*(baseline|snapshot|export|dump|diagnostic).*(\.json|\.ya?ml|\.txt|\.conf)?$' placeholder_regex='(REDACTED|CHANGE_ME||example|placeholder|your[_ -]?token|your[_ -]?key)' declare -a files=() if [[ "$mode" == "--staged" ]]; then while IFS= read -r f; do [[ -n "$f" ]] && files+=("$f") done < <(git diff --cached --name-only --diff-filter=ACMR) else shift for f in "$@"; do files+=("$f") done fi if [[ ${#files[@]} -eq 0 ]]; then exit 0 fi failures=0 scan_file() { local file="$1" [[ -f "$file" ]] || return 0 [[ "$file" =~ $artifact_path_regex ]] || return 0 python3 - "$file" "$placeholder_regex" <<'PY' from pathlib import Path import re, sys path = Path(sys.argv[1]) placeholder = re.compile(sys.argv[2], re.I) text = path.read_text(errors='ignore') lines = text.splitlines() patterns = [ (re.compile(r'"x_wireguard_private_key"\s*:\s*"([^"]+)"', re.I), 'embedded WireGuard private key'), (re.compile(r'"wireguard_client_configuration_file"\s*:\s*"([^"\\]|\\.)*PrivateKey = [A-Za-z0-9+/=]{20,}', re.I), 'embedded WireGuard client config with private key'), (re.compile(r'PrivateKey\s*=\s*([A-Za-z0-9+/=]{20,})'), 'WireGuard private key line'), (re.compile(r'Authorization\s*[:=]\s*(Bearer\s+)?[A-Za-z0-9._~+/=-]{16,}', re.I), 'authorization header/token material'), (re.compile(r'"(token|api[_-]?key|client[_-]?secret|password|secret|cookie)"\s*:\s*"([^"]{12,})"', re.I), 'suspicious secret-like JSON field'), ] for idx, line in enumerate(lines, start=1): for regex, label in patterns: m = regex.search(line) if not m: continue if placeholder.search(line): continue print(f'{path}:{idx}: {label}') print(f' {line[:220]}') sys.exit(1) sys.exit(0) PY } for file in "${files[@]}"; do if ! scan_file "$file"; then failures=1 fi done if [[ "$failures" -ne 0 ]]; then cat >&2 <<'EOF' Secret-bearing artifact scan failed. This guardrail is intentionally narrow: it is meant to stop raw controller/export/baseline artifacts from being committed with embedded keys or tokens. Fix options: - remove the raw artifact from the commit - replace it with a sanitized markdown summary - explicitly redact the secret-bearing fields If raw retention is required, store it outside the main repo or in the encrypted secrets repo. EOF exit 1 fi