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.
170 lines
6.0 KiB
Markdown
170 lines
6.0 KiB
Markdown
# 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.
|