Enabling real scanner backends (Trivy / Grype)
OrbitalReg's Detection queue runs seven scanner adapters out of the box: orbital.signature.v1, orbital.sbom-extract.v1, orbital.secret.v1, orbital.license.v1, orbital.banned-api.v1, and two out-of-process CVE scanners, external.trivy.v1 (Aqua Trivy) and external.grype.v1 (Anchore Grype). The first five are in-process, always registered, and run automatically. Trivy and Grype shell out to a real binary and are opt-in per project — this page covers what it takes to turn them on.
Cost classes
Every scanner declares a cost class that controls whether it runs by default:
| Cost class | Scanners | Default per project |
|---|---|---|
cheap | signature | Runs automatically |
medium | sbom-extract, secret, license, banned-api | Runs automatically |
heavy | external.trivy.v1, external.grype.v1 | Skipped until opted in |
A project's scan rules (see Scanning and Detection) leave scanner_set empty by default, which means "every enabled cheap/medium scanner, no heavy scanners" — the heavy gate exists so that installing the platform doesn't silently start shelling out to Trivy/Grype on every upload before an operator has decided they want that cost. Concurrent heavy jobs across the whole deployment are capped by ORBITALREG_SCAN_HEAVY_CONCURRENCY (default 2 per pod), independent of the per-project opt-in.
1. Install the binary
Trivy and Grype are external binaries, not Go dependencies — they are not bundled with the OrbitalReg image. Install one or both on every pod/host that runs the API's background scan dispatcher:
- Trivy: see the official install docs.
- Grype: see the official install docs.
By default each adapter resolves its binary via PATH. To pin an explicit path (recommended for immutable/distroless images, where the binary is baked in at a known location), set:
| Env var | Scanner | Default |
|---|---|---|
ORBITALREG_TRIVY_BIN | Trivy | trivy on PATH |
ORBITALREG_GRYPE_BIN | Grype | grype on PATH |
If neither the env var nor a PATH lookup resolves a binary, the scanner fails its job with trivy not installed (set ORBITALREG_TRIVY_BIN or install \trivy` on PATH)` (or the Grype equivalent) instead of silently skipping — the Detection queue surfaces the failed job so the gap is visible rather than a quiet no-op.
2. Enable the scanner for a project
Per-project opt-in lives in scan_rules.scanner_set, edited via the Detection → Scanners UI or directly through the API:
curl -fsS -X PUT \
"https://<your-instance>/api/v1/detection/rules?project=<project-slug>" \
-H "Content-Type: application/json" \
--cookie "<session-cookie>" \
-d '{
"enabled": true,
"fail_on": "high",
"scanner_set": ["external.trivy.v1", "external.grype.v1"]
}'An empty scanner_set means "every non-heavy scanner"; listing external.trivy.v1 and/or external.grype.v1 explicitly is what opts a project into the heavy scanners. Both can run side by side — most operators standardise on one, but running both is useful while comparing coverage during a migration.
3. Confirm it's running
Upload an artifact to the project and poll the queue:
curl -fsS "https://<your-instance>/api/v1/detection/scans?project=<project-slug>" \
--cookie "<session-cookie>"A scan_jobs row for external.trivy.v1 / external.grype.v1 moves from queued → running → done (or failed, with the binary-missing message above if the install step was skipped). Findings then appear under GET /api/v1/detection/findings.
Known limits
- Per-job budget. The dispatcher wraps every scan job — regardless of cost class — in a 60-second execution budget. A cold Trivy vulnerability-database load or an unusually large artifact can exceed that window; the job then fails with a
context deadline exceedederror rather than a clean partial result. If you see this in practice, warm Trivy's DB cache ahead of time (trivy image --download-db-only) or scope scans to smaller artifacts until the dispatcher grows a heavy-class-aware budget. - JSON stdout only. Both adapters spool the artifact body to a tempfile and shell out with
--format json/--output json; anything that changes the binary's default output format (a customtrivy.yaml, a Grype config pointing at a non-JSON template) breaks the parser. Don't override the output format in binary-level config used by OrbitalReg's dispatcher. - No bundled CVE database. Both tools fetch their own vulnerability database independently (Trivy from its GHCR mirror, Grype from Anchore's feed service) — see each project's own docs for air-gapped database mirroring if your deployment has no outbound internet access.