Skip to content

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 classScannersDefault per project
cheapsignatureRuns automatically
mediumsbom-extract, secret, license, banned-apiRuns automatically
heavyexternal.trivy.v1, external.grype.v1Skipped 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:

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 varScannerDefault
ORBITALREG_TRIVY_BINTrivytrivy on PATH
ORBITALREG_GRYPE_BINGrypegrype 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:

bash
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:

bash
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 queuedrunningdone (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 exceeded error 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 custom trivy.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.

Released under the Apache-2.0 License.