#!/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"