---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.
6.0 KiB
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
# 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 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/randinstead ofcrypto/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 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=modforces module mode (avoids surprise network fetches during the build).- The
GOVULNCHECK_DBenvironment 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 withgovulncheck -show=verboseonce per week on a machine that has network access, then commit the resultingvulndbartifact 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 everygovulncheckrelease; in CI we pin tov1.1.3for 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 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.envSHA-1 leak from v0.1 history (rotated forward; the baseline gates future re-leaks of the same SHA).- Pre-commit hook (
.githooks/pre-commit) — runsgitleaks protect --stagedon every commit. Commits are still allowed when gitleaks is not installed (theif command -vgate is in the hook).
Pipeline Integration
.coreci.yml validate pipeline:
- 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):
- name: test
image: golang:1.25
commands:
- go test -race -coverprofile=coverage.out ./...
- go tool cover -func=coverage.out | tail -1
Local development
# 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:
- gosec: regenerate the baseline with
gosec -fmt json -no-fail ./... > gosec.json. Inspect for false positives; document the suppression in the JSON'ssuppressionsfield. - govulncheck: wait for the upstream fix; if you must pin
a vulnerable dep, document the pin in a
//nolint:govulncheckcomment and create a tracking issue. - gitleaks: add a fingerprint to
.gitleaks-baseline.jsonwithgitleaks detect --baseline-path .gitleaks-baseline.json --report-path new-findings.jsonfirst 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:
GOFLAGS=-mod=modensures module mode (no surprise module downloads).- The pre-mirrored DB mechanism is a follow-up; the bundled DB
in the pinned
govulncheckbinary is the immediate fallback. - CI runs in a controlled environment (CoreCI runner) where the
GOVULNCHECK_DBenv 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.