#!/usr/bin/env bash
#
# Balinyaar secret-scanning pre-commit hook (refinement-phase-5).
# Blocks a commit that stages an obvious credential. This is a fast, dependency-free backstop for the
# root CLAUDE.md rule "Never commit secrets" — not a replacement for gitleaks/trufflehog in CI.
#
# Enable once per clone:   git config core.hooksPath .githooks
# Bypass a false positive:  git commit --no-verify   (use sparingly, and only when you are certain)
#
set -euo pipefail

# Committed placeholders are allowed — real values are not. Keep in sync with StartupSecretsGuard.
PLACEHOLDER='SET_VIA_USER_SECRETS_OR_ENV'

# Files that deliberately carry live deployment credentials, because the pre-launch demo deployment
# configures itself from committed files rather than a secret store (see DEPLOY.md). They are exempt from
# the connection-string and known-host checks ONLY — the private-key and AWS-key checks still apply to
# them, and every other file in the repo is scanned exactly as strictly as before.
#
# This list is the honest record of where the repo's secrets are. Shrink it, never grow it: the moment
# real users exist, these values must be rotated and moved out of git.
declared_config() {
  case "$1" in
    server/src/API/Baya.Web.Api/appsettings.Development.json) return 0 ;;
    docker-compose.yml) return 0 ;;
    telegram-otp-bot/.env.example) return 0 ;;
    DEPLOY.md) return 0 ;;
    *) return 1 ;;
  esac
}

# Only scan added/changed lines in text files that are staged.
staged=$(git diff --cached --name-only --diff-filter=ACM)
[ -z "$staged" ] && exit 0

violations=0
report() { printf '  ✖ %s\n' "$1"; violations=$((violations + 1)); }

while IFS= read -r file; do
  # Skip this hook, lockfiles, and binaries.
  case "$file" in
    .githooks/*) continue ;;
    *.png|*.jpg|*.jpeg|*.gif|*.ico|*.pdf|*.dll|*.exe|*.snk) continue ;;
  esac
  [ -f "$file" ] || continue

  added=$(git diff --cached -U0 -- "$file" | grep '^+' | grep -v '^+++' || true)
  [ -z "$added" ] && continue

  # The retired hardcoded admin password. Applies everywhere, no exemptions.
  echo "$added" | grep -Eq 'qw123321' && report "$file: hardcoded admin password 'qw123321'"

  if ! declared_config "$file"; then
    # The deployment's SQL Server host — outside the declared config files it is a leak.
    echo "$added" | grep -Eq '87\.107\.152\.16' && report "$file: SQL Server host 87.107.152.16 outside the declared config files"

    # A real (non-placeholder) connection-string password in a committed appsettings file.
    case "$file" in
      *appsettings*.json)
        echo "$added" \
          | grep -Ei 'Password=[^;"'"'"' ]+' \
          | grep -viq "Password=${PLACEHOLDER}" \
          && report "$file: connection-string password must be '${PLACEHOLDER}' (see DEPLOY.md for where real values live)"
        ;;
    esac
  fi

  # Private keys and common cloud tokens, anywhere.
  echo "$added" | grep -Eq -- '-----BEGIN (RSA|EC|OPENSSH|PRIVATE) .*PRIVATE KEY-----' && report "$file: private key material"
  echo "$added" | grep -Eq 'AKIA[0-9A-Z]{16}' && report "$file: AWS access key id"
done <<< "$staged"

if [ "$violations" -gt 0 ]; then
  echo ""
  echo "Commit blocked: $violations potential secret(s) staged. Real values belong in one of the declared"
  echo "config files (see the 'declared_config' list in this hook, and DEPLOY.md); everything else commits"
  echo "only the '${PLACEHOLDER}' placeholder."
  echo "To override a false positive: git commit --no-verify"
  exit 1
fi

exit 0
