#!/bin/bash
# security_scan.sh — run gosec, govulncheck, and gitleaks on the
# orca repo. Local equivalent of the .coreci.yml `validate` security
# stages. Exits non-zero on any unsuppressed finding.
#
# Tool detection: a tool that's not installed is SKIPPED (warning
# printed). The .coreci.yml `validate` pipeline requires all three;
# the local `make security-scan` is opt-in for developer machines.
#
# Usage: scripts/security_scan.sh [--strict]
#   --strict  All three tools must be present and pass.
#
# REQ-014: gosec + govulncheck in CI
# REQ-027: govulncheck runs in offline mode
# REQ-039: gitleaks allowlist for cert PEM blocks
# REQ-040: golangci-lint as the unified linter

set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
cd "$REPO_ROOT"

STRICT=false
if [ "${1:-}" = "--strict" ]; then
  STRICT=true
fi

PASS=0
FAIL=0
SKIP=0

run_tool() {
  local name="$1"
  shift
  echo ""
  echo "─── $name ─────────────────────────────────────"
  if "$@"; then
    echo "✓ $name: PASS"
    PASS=$((PASS+1))
  else
    rc=$?
    if [ $rc -eq 127 ]; then
      echo "⚠ $name: SKIP (not installed)"
      SKIP=$((SKIP+1))
    else
      echo "✗ $name: FAIL (rc=$rc)"
      FAIL=$((FAIL+1))
    fi
  fi
}

# gosec: static analysis. REQ-014 baseline is empty (clean repo);
# any new G101 (hardcoded credentials) fails the build.
run_gosec() {
  if ! command -v gosec >/dev/null 2>&1; then
    return 127
  fi
  gosec -fmt text -quiet ./...
}

# govulncheck: vulnerability scan. REQ-027: offline mode.
# We rely on the bundled DB; the `GOVULNCHECK_DB` env var (when
# present) overrides. This is documented in docs/security-scanning.md.
run_govulncheck() {
  if ! command -v govulncheck >/dev/null 2>&1; then
    return 127
  fi
  GOFLAGS=-mod=mod govulncheck -mode binary ./... >/dev/null
}

# gitleaks: secret scan. REQ-039 allowlist via .gitleaks.toml;
# REQ-029 baseline via .gitleaks-baseline.json.
run_gitleaks() {
  if ! command -v gitleaks >/dev/null 2>&1; then
    return 127
  fi
  if [ ! -f .gitleaks-baseline.json ]; then
    echo "  (no .gitleaks-baseline.json; first run will be unfiltered)"
  fi
  gitleaks detect --source . --config .gitleaks.toml --baseline-path .gitleaks-baseline.json --no-banner
}

run_tool "gosec"        run_gosec
run_tool "govulncheck"  run_govulncheck
run_tool "gitleaks"     run_gitleaks

echo ""
echo "─── summary ─────────────────────────────────────"
echo "  $PASS pass, $FAIL fail, $SKIP skip"
echo ""

if [ $FAIL -gt 0 ]; then
  echo "✗ security-scan FAILED ($FAIL tool(s) reported findings)"
  exit 1
fi

if $STRICT && [ $SKIP -gt 0 ]; then
  echo "✗ security-scan FAILED in --strict mode ($SKIP tool(s) skipped)"
  exit 2
fi

echo "✓ security-scan PASSED"
