#!/usr/bin/env bash
set -euo pipefail

repo_root="$(git rev-parse --show-toplevel)"
cd "$repo_root"

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|<redacted>|example|placeholder|your[_ -]?token|your[_ -]?key)'
empty_tree='4b825dc642cb6eb9a060e54bf8d69288fbee4904'

usage() {
  cat >&2 <<'EOF'
usage:
  scripts/scan-secret-bearing-artifacts.sh --staged
  scripts/scan-secret-bearing-artifacts.sh --tracked
  scripts/scan-secret-bearing-artifacts.sh --files <path> ...
  scripts/scan-secret-bearing-artifacts.sh --git-range <revset>
  scripts/scan-secret-bearing-artifacts.sh --unpublished <tip-commit>
EOF
  exit 2
}

mode="${1:---staged}"
shift || true

declare -a files=()
declare -a commit_specs=()

case "$mode" in
  --staged)
    while IFS= read -r -d '' f; do
      files+=("$f")
    done < <(git diff --cached --name-only --diff-filter=ACMR -z)
    ;;
  --tracked)
    while IFS= read -r -d '' f; do
      files+=("$f")
    done < <(git ls-files -z)
    ;;
  --files)
    [[ $# -ge 1 ]] || usage
    files=("$@")
    ;;
  --git-range)
    [[ $# -eq 1 ]] || usage
    while IFS= read -r commit; do
      [[ -n "$commit" ]] && commit_specs+=("$commit")
    done < <(git rev-list --reverse "$1")
    ;;
  --unpublished)
    [[ $# -eq 1 ]] || usage
    while IFS= read -r commit; do
      [[ -n "$commit" ]] && commit_specs+=("$commit")
    done < <(git rev-list --reverse "$1" --not --remotes)
    ;;
  *)
    usage
    ;;
esac

if [[ ${#files[@]} -eq 0 && ${#commit_specs[@]} -eq 0 ]]; then
  exit 0
fi

python_scan() {
  local display_name="$1"
  local source_mode="$2"
  local source_value="$3"

  python3 - "$display_name" "$placeholder_regex" "$source_mode" "$source_value" <<'PY'
from pathlib import Path
import re
import subprocess
import sys

label = sys.argv[1]
placeholder = re.compile(sys.argv[2], re.I)
source_mode = sys.argv[3]
source_value = sys.argv[4]

if source_mode == 'file':
    text = Path(source_value).read_text(errors='ignore')
else:
    text = subprocess.check_output(
        ['git', 'show', source_value],
        text=True,
        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'BEGIN [A-Z0-9 ]*PRIVATE KEY', re.I), 'private key block header'),
    (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, finding in patterns:
        match = regex.search(line)
        if not match:
            continue
        if placeholder.search(line):
            continue
        print(f'{label}:{idx}: {finding}')
        print(f'  {line[:220]}')
        sys.exit(1)
sys.exit(0)
PY
}

scan_worktree_file() {
  local file="$1"
  [[ -f "$file" ]] || return 0
  [[ "$file" =~ $artifact_path_regex ]] || return 0
  python_scan "$file" file "$file"
}

scan_commit_file() {
  local commit="$1"
  local file="$2"
  git cat-file -e "$commit:$file" 2>/dev/null || return 0
  [[ "$file" =~ $artifact_path_regex ]] || return 0
  python_scan "$commit:$file" git_object "$commit:$file"
}

failures=0

if [[ ${#files[@]} -gt 0 ]]; then
  for file in "${files[@]}"; do
    if ! scan_worktree_file "$file"; then
      failures=1
    fi
  done
fi

if [[ ${#commit_specs[@]} -gt 0 ]]; then
  declare -A seen=()
  for commit in "${commit_specs[@]}"; do
    parent="$empty_tree"
    if git rev-parse --verify "$commit^" >/dev/null 2>&1; then
      parent="$commit^"
    fi
    while IFS= read -r -d '' file; do
      key="$commit:$file"
      [[ -n "$file" ]] || continue
      [[ -n "${seen[$key]:-}" ]] && continue
      seen[$key]=1
      if ! scan_commit_file "$commit" "$file"; then
        failures=1
      fi
    done < <(git diff --name-only --diff-filter=ACMR -z "$parent" "$commit")
  done
fi

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 or pushed 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
