#!/usr/bin/env bash
# =============================================================================
# secret-scan.sh — Pre-commit credential leak detector
#
# Usage:
#   Run directly:        bash scripts/secret-scan.sh
#   As a Husky hook:     echo 'bash scripts/secret-scan.sh' >> .husky/pre-commit
#
# What it checks (staged files only, falls back to full tree):
#   • Raw Ethereum / EVM private keys (64-char hex)
#   • NPM automation tokens  (npm_...)
#   • Vercel tokens          (vcp_... / vercel_...)
#   • Generic high-entropy secrets in common env-var patterns
#   • Hardcoded OPENAI / ANTHROPIC API keys
#   • AWS access key IDs
#   • GitHub personal access tokens
#
# Exit codes:
#   0 — clean
#   1 — potential secrets found (commit blocked)
# =============================================================================

set -euo pipefail

RED='\033[0;31m'
YELLOW='\033[1;33m'
GREEN='\033[0;32m'
NC='\033[0m' # no colour

FOUND=0

# ---------------------------------------------------------------------------
# Determine files to scan
# ---------------------------------------------------------------------------
# If running inside a git repo with staged changes, scan only staged files.
# Otherwise fall back to the full working tree (useful for CI).
if git rev-parse --git-dir >/dev/null 2>&1; then
  FILES=$(git diff --cached --name-only --diff-filter=ACM 2>/dev/null || true)
else
  FILES=$(find . -type f \
    ! -path '*/node_modules/*' \
    ! -path '*/.git/*' \
    ! -path '*/dist/*' \
    ! -path '*/.next/*' \
    ! -path '*/build/*')
fi

if [ -z "$FILES" ]; then
  echo -e "${GREEN}✔ No staged files to scan.${NC}"
  exit 0
fi

# ---------------------------------------------------------------------------
# Helper: scan a single pattern across all files
# ---------------------------------------------------------------------------
scan_pattern() {
  local label="$1"
  local pattern="$2"
  local hits

  hits=$(echo "$FILES" | xargs grep -lE "$pattern" 2>/dev/null \
         | grep -v 'secret-scan\.sh' \
         | grep -v '\.example$' \
         | grep -v '\.template$' \
         | grep -v '\.sample$' \
         || true)

  if [ -n "$hits" ]; then
    # Filter out files where every match is on a line tagged with
    # `secret-scan: ignore` or `pragma: allowlist secret`.
    local real_hits=""
    while read -r f; do
      [ -z "$f" ] && continue
      # Get matching lines that are NOT allowlisted
      local bad_lines
      bad_lines=$(grep -nE "$pattern" "$f" 2>/dev/null \
                  | grep -v -E '(secret-scan:\s*ignore|pragma:\s*allowlist\s*secret|never\s*held\s*funds|test-only key|hard-coded test private keys|test-only)' \
                  || true)
      if [ -n "$bad_lines" ]; then
        real_hits="${real_hits}${f}\n"
      fi
    done <<< "$hits"

    if [ -n "$real_hits" ]; then
      echo -e "${RED}[BLOCKED] Potential secret detected — ${label}${NC}"
      echo -e "$real_hits" | while read -r f; do
        [ -z "$f" ] && continue
        echo -e "  ${YELLOW}→ $f${NC}"
        grep -nE "$pattern" "$f" 2>/dev/null \
          | grep -v -E '(secret-scan:\s*ignore|pragma:\s*allowlist\s*secret|never\s*held\s*funds|test-only key|hard-coded test private keys|test-only)' \
          | sed 's/\(.\{60\}\).*/\1…/' \
          | head -5 \
          | sed 's/^/    /'
      done
      FOUND=1
    fi
  fi
}

echo "Scanning $(echo "$FILES" | wc -l | tr -d ' ') file(s) for credentials…"

# ---------------------------------------------------------------------------
# Pattern library
# ---------------------------------------------------------------------------

# Raw EVM private key: 0x + 64 hex chars, OR bare 64 hex chars assigned to a
# variable that looks like a private/secret key name
scan_pattern \
  "EVM private key (0x64hex)" \
  '0x[0-9a-fA-F]{64}'

scan_pattern \
  "bare hex private key in env assignment" \
  '(PRIVATE_KEY|DEPLOYER_KEY|SECRET_KEY)\s*=\s*["'"'"']?[0-9a-fA-F]{64}["'"'"']?'

# NPM tokens
scan_pattern \
  "NPM automation token (npm_...)" \
  'npm_[A-Za-z0-9]{36}'

# Vercel tokens
scan_pattern \
  "Vercel token (vcp_... / vercel_...)" \
  '(vcp_|vercel_)[A-Za-z0-9_\-]{20,}'

# OpenAI keys
scan_pattern \
  "OpenAI API key (sk-...)" \
  'sk-[A-Za-z0-9]{32,}'

# Anthropic keys
scan_pattern \
  "Anthropic API key" \
  'sk-ant-[A-Za-z0-9\-_]{40,}'

# AWS access key IDs
scan_pattern \
  "AWS access key ID (AKIA...)" \
  'AKIA[0-9A-Z]{16}'

# GitHub PATs (classic and fine-grained)
scan_pattern \
  "GitHub personal access token" \
  'gh[pousr]_[A-Za-z0-9_]{36,}'

# Generic high-entropy secret in common assignment patterns
scan_pattern \
  "generic secret assignment (API_KEY / TOKEN / PASSWORD = long string)" \
  '(API_KEY|API_SECRET|AUTH_TOKEN|ACCESS_TOKEN|PASSWORD|PASSWD|SECRET)\s*=\s*["'"'"'][A-Za-z0-9+/=_\-]{32,}["'"'"']'

# ---------------------------------------------------------------------------
# Result
# ---------------------------------------------------------------------------
if [ "$FOUND" -eq 1 ]; then
  echo ""
  echo -e "${RED}╔══════════════════════════════════════════════════════╗${NC}"
  echo -e "${RED}║  COMMIT BLOCKED — Potential secrets detected above.  ║${NC}"
  echo -e "${RED}║                                                      ║${NC}"
  echo -e "${RED}║  Remove the secrets, rotate any that were exposed,   ║${NC}"
  echo -e "${RED}║  and use environment variables or a secrets manager. ║${NC}"
  echo -e "${RED}╚══════════════════════════════════════════════════════╝${NC}"
  exit 1
fi

echo -e "${GREEN}✔ No credential patterns detected. Safe to commit.${NC}"
exit 0
