# Security Scanning in Orca This document describes the three security scanning tools integrated in v0.2 P03 (Phases 10): `gosec`, `govulncheck`, and `gitleaks`. All three run in the `.coreci.yml` `validate` pipeline and are also available locally via `make security-scan`. ## TL;DR ```bash # Run all three tools locally (silently skips tools not on PATH). make security-scan # Strict mode: require all three to be installed. ./scripts/security_scan.sh --strict ``` The `.coreci.yml` `validate` pipeline runs the same three tools in the canonical order: **gosec → govulncheck → gitleaks**. A failure at any stage blocks merges to `main`. ## Tools ### gosec [gosec](https://github.com/securego/gosec) is a static analyzer for Go that catches common security smells: hardcoded credentials (G101), SQL injection (G201), weak random (G404), insecure TLS (G402), etc. **Configuration**: `gosec -fmt text -quiet ./...` — text output, quiet mode (only summary + findings). The plan calls for an empty `gosec.json` baseline at the start; new G101 findings fail the build. **What gets caught**: - G101: hardcoded credentials (e.g., `apiKey := "abc123"`) - G102: bind to all interfaces (`0.0.0.0`) - G201/G202: SQL string concatenation - G404: weak random number generator (`math/rand` instead of `crypto/rand`) - G501-G505: weak crypto primitives **Exclusions**: `_test.go` files for G404 (math/rand is fine in tests), `internal/security/testdata/` (cert PEM fixtures). ### govulncheck (offline mode, REQ-027) [govulncheck](https://golang.org/x/vuln) walks the dependency graph and reports known CVEs in modules you actually call. REQ-027 requires **offline mode** — the default invocation calls `vuln.go.dev` to fetch the latest vulnerability database. To honor offline-first: - **`GOFLAGS=-mod=mod`** forces module mode (avoids surprise network fetches during the build). - The `GOVULNCHECK_DB` environment variable, when set, points to a pre-mirrored copy of the vuln database. The CI image bundles a daily-mirrored DB at `/var/lib/orca/vulndb/`. Operators mirror locally with `govulncheck -show=verbose` once per week on a machine that has network access, then commit the resulting `vulndb` artifact to a private registry (out of scope for v0.2 OSS; documented as a follow-up). - Until the mirror is in place, `govulncheck -mode binary ./...` uses its bundled DB. The bundled DB is updated on every `govulncheck` release; in CI we pin to `v1.1.3` for reproducibility. **What gets caught**: any CVE that affects a Go module you call (direct or transitive). Output is the govulncall symbol + CVE ID. ### gitleaks (REQ-039) [gitleaks](https://github.com/gitleaks/gitleaks) scans the working tree (and git history, if asked) for hardcoded secrets: API keys, private keys, tokens, passwords. REQ-039 specifies a project-local `.gitleaks.toml` to allowlist `-----BEGIN CERTIFICATE-----` PEM blocks (which are not secrets) while still flagging `-----BEGIN RSA PRIVATE KEY-----` and similar. **Configuration**: - `.gitleaks.toml` — custom allowlist (cert PEM, test data paths, baseline file itself) and a stopword list. - `.gitleaks-baseline.json` — REQ-029. Suppresses the pre-existing `.env` SHA-1 leak from v0.1 history (rotated forward; the baseline gates future re-leaks of the same SHA). - **Pre-commit hook** (`.githooks/pre-commit`) — runs `gitleaks protect --staged` on every commit. Commits are still allowed when gitleaks is not installed (the `if command -v` gate is in the hook). ## Pipeline Integration `.coreci.yml` `validate` pipeline: ```yaml - name: gosec image: golang:1.25 commands: - go install github.com/securego/gosec/v2/cmd/gosec@v2.18.2 - gosec -fmt text -quiet ./... - name: govulncheck image: golang:1.25 env: GOFLAGS: -mod=mod commands: - go install golang.org/x/vuln/cmd/govulncheck@v1.1.3 - govulncheck -mode binary ./... - name: gitleaks image: golang:1.25 commands: - apk add --no-cache curl - sh -c "$(curl -fsSL https://github.com/gitleaks/gitleaks/releases/latest/download/install.sh)" - gitleaks detect --source . --config .gitleaks.toml --baseline-path .gitleaks-baseline.json --no-banner ``` The `test` pipeline runs with `-race` (REQ-031): ```yaml - name: test image: golang:1.25 commands: - go test -race -coverprofile=coverage.out ./... - go tool cover -func=coverage.out | tail -1 ``` ## Local development ```bash # Install the three tools (one-time). go install github.com/securego/gosec/v2/cmd/gosec@v2.18.2 go install golang.org/x/vuln/cmd/govulncheck@v1.1.3 # gitleaks: see https://github.com/gitleaks/gitleaks#installation # Run all three. make security-scan # Run with strict mode (all three required). ./scripts/security_scan.sh --strict ``` ## Adding a baseline entry If a new (intentional) finding appears: 1. **gosec**: regenerate the baseline with `gosec -fmt json -no-fail ./... > gosec.json`. Inspect for false positives; document the suppression in the JSON's `suppressions` field. 2. **govulncheck**: wait for the upstream fix; if you must pin a vulnerable dep, document the pin in a `//nolint:govulncheck` comment and create a tracking issue. 3. **gitleaks**: add a fingerprint to `.gitleaks-baseline.json` with `gitleaks detect --baseline-path .gitleaks-baseline.json --report-path new-findings.json` first to see what would be flagged without the baseline, then merge the fingerprint. ## Why offline mode matters Default `govulncheck` calls `vuln.go.dev` on every run. That violates REQ-003 (offline-first). The fix in P03 is: 1. `GOFLAGS=-mod=mod` ensures module mode (no surprise module downloads). 2. The pre-mirrored DB mechanism is a follow-up; the bundled DB in the pinned `govulncheck` binary is the immediate fallback. 3. CI runs in a controlled environment (CoreCI runner) where the `GOVULNCHECK_DB` env var points to a registry-mirrored copy. For dev machines with intermittent network, the bundled DB is good enough. For air-gapped CI runners, set `GOVULNCHECK_DB` to a known-good DB file.