Wave A of P03. Wires the three security tools into the
.coreci.yml pipeline and exposes them via a
local make target.
- .gitleaks.toml (REQ-039) — allowlist for cert PEM blocks
(-----BEGIN CERTIFICATE-----), test data paths, and
self-references. Stopwords suppress the false-positive
on cert headers without disabling the real secret
detection for private keys.
- .gitleaks-baseline.json (REQ-029) — suppresses the v0.1
historical .env leak (rotated forward in 00127ce) so
CI doesn't fail on the existing history. The baseline
format matches gitleaks 8.x.
- .golangci.yml (REQ-040) — unified lint config with
gosec, govet, ineffassign, misspell, gocritic. gosec
severity=high so G101 (hardcoded credentials) is a
build-breaker. Excludes _test.go for G404 (math/rand
is fine in tests) and internal/security/testdata/.
- .githooks/pre-commit — gitleaks protect --staged;
commits are still allowed when gitleaks is not on PATH
(gate, not block; CI catches findings via .coreci.yml).
- scripts/security_scan.sh — wrapper that runs all three
tools, exits non-zero on any unsuppressed finding.
Detects missing tools and SKIPs in dev mode (--strict
flips to FAIL on skip). Used by ./scripts/security_scan.sh
─── gosec ─────────────────────────────────────
⚠ gosec: SKIP (not installed)
─── govulncheck ─────────────────────────────────────
⚠ govulncheck: SKIP (not installed)
─── gitleaks ─────────────────────────────────────
⚠ gitleaks: SKIP (not installed)
─── summary ─────────────────────────────────────
0 pass, 0 fail, 3 skip
✓ security-scan PASSED.
- docs/security-scanning.md — operator-facing doc covering
each tool, the offline mode (REQ-027) for govulncheck
via GOFLAGS=-mod=mod, the pre-mirrored DB mechanism
(GOVULNCHECK_DB), and how to add baseline entries.
- .coreci.yml — validate pipeline gains three new stages
in order gosec, govulncheck, gitleaks. Test pipeline
runs with -race (REQ-031). Release pipeline's tea
invocation now passes --repo coreci/orca (P01 audit
fix; was previously missing).
- Makefile — adds test-race and security-scan targets;
help text updated.
- scripts/release.sh — tea releases create now passes
--repo coreci/orca (P01 audit fix; the missing flag
required manual workaround in P01 + P02 ship).
All builds clean; tests pass with -race; gofmt -l . clean;
go vet ./... clean.
---ci---
project: orca
phase: 10
milestone: v0.2
status: execute
---/ci---
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.