#!/usr/bin/env bash
# net-kingdom pre-commit hook — blocks plaintext secrets from entering git.
#
# Enabled by: make hooks  (sets core.hooksPath = .githooks)
# Tested by:  make hooks-test
#
# BLOCKS:
#   1. Any file under secrets/ without a SOPS marker
#   2. Any *.env file outside sso-mfa/bootstrap/ (env files contain raw secrets)
#   3. Any staged file containing known plaintext secret patterns
#
# WARNS:
#   - Bundle archives (*-bundle*.tar.age) — these belong offsite, not in git

set -euo pipefail

fail=0

# ── Helper ────────────────────────────────────────────────────────────────────
staged_files() {
    git diff --cached --name-only --diff-filter=ACMR
}

file_content() {
    git show ":$1" 2>/dev/null || true
}

# ── Check 1: secrets/ files must be SOPS-encrypted ───────────────────────────
secrets_files=$(staged_files | grep -E '(^|/)secrets/' || true)

if [[ -n "$secrets_files" ]]; then
    while IFS= read -r f; do
        [[ -z "$f" ]] && continue
        content="$(file_content "$f")"
        [[ -z "$content" ]] && continue
        # SOPS-encrypted files contain a top-level 'sops:' or '"sops":' key
        if echo "$content" | grep -qE '^[[:space:]]*sops:[[:space:]]*$|"sops"[[:space:]]*:'; then
            continue
        fi
        # Also allow binary age-encrypted or gpg-encrypted blobs
        case "$f" in
            *.age|*.gpg) continue ;;
        esac
        echo "  [secrets/] not SOPS-encrypted: $f"
        fail=1
    done <<< "$secrets_files"
fi

# ── Check 2: *.env files outside sso-mfa/bootstrap/ ─────────────────────────
env_files=$(staged_files | grep -E '\.env$' | grep -v '^sso-mfa/bootstrap/' || true)

if [[ -n "$env_files" ]]; then
    while IFS= read -r f; do
        [[ -z "$f" ]] && continue
        echo "  [*.env outside bootstrap/] $f"
        fail=1
    done <<< "$env_files"
fi

# ── Check 3: known plaintext secret patterns in any staged file ───────────────
# These patterns appear only in generated secrets files — never in code.
FORBIDDEN_PATTERNS=(
    'PI_SECRET_KEY='
    'PI_PEPPER='
    'LLDAP_JWT_SECRET='
    'AUTHELIA_JWT_SECRET='
    'AUTHELIA_SESSION_SECRET='
    'AUTHELIA_STORAGE_ENCRYPTION_KEY='
    'AUTHELIA_OIDC_HMAC_SECRET='
    'AUTHELIA_KEYCAPE_CLIENT_SECRET='
    'BREAKGLASS_PASSWORD='
    'PG_ROOT_PASSWORD='
)

while IFS= read -r f; do
    [[ -z "$f" ]] && continue
    content="$(file_content "$f")"
    [[ -z "$content" ]] && continue
    for pat in "${FORBIDDEN_PATTERNS[@]}"; do
        if echo "$content" | grep -qF "$pat"; then
            echo "  [secret pattern '$pat'] $f"
            fail=1
        fi
    done
done <<< "$(staged_files)"

# ── Warning: bundle archives in git ──────────────────────────────────────────
bundle_files=$(staged_files | grep -E '\-bundle.*\.tar\.age$' || true)

if [[ -n "$bundle_files" ]]; then
    echo ""
    echo "WARN: ops bundle archives detected — these belong offsite, not in git:"
    while IFS= read -r f; do
        echo "  $f"
    done <<< "$bundle_files"
    echo ""
fi

# ── Result ────────────────────────────────────────────────────────────────────
if [[ "$fail" -ne 0 ]]; then
    echo ""
    echo "Commit blocked: plaintext secret(s) detected (see above)."
    echo ""
    echo "To encrypt a file with SOPS:   sops --encrypt --in-place <file>"
    echo "To edit an encrypted file:     sops <file>"
    echo "To bypass (never in prod):     git commit --no-verify"
    exit 1
fi

exit 0
