df58bc25a3
---ci--- project: orca phase: 3 milestone: v0.3 status: complete requirements: covered: [REQ-022, REQ-030, REQ-032] partial: [] ---/ci--- v0.3 milestone merged to main. Includes all v0.2 work (P08-P10) that was previously on the milestone branch but not yet merged to main, plus the v0.3 completion work (iter.Seq streaming + doctor network/db). v0.2 phases included: P08 (mTLS), P09 (scheduling), P10 (security scan). v0.3 phases: P0 (pre-execution), P1 (iter.Seq streaming), P2 (doctor), P3 (final review+ship). Total: 40 requirements, all complete. No new go.mod dependencies. Full test suite passes under -race. gofmt + go vet clean.
104 lines
2.9 KiB
Bash
Executable File
104 lines
2.9 KiB
Bash
Executable File
#!/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"
|