VEX & vulnerability scanning
The component scans the SBOM with Grype, applies OpenVEX exceptions so a known-not-affected CVE doesn’t block your release, and gates on Critical findings. This page explains the scan, the VEX layer, and why scanning and gating are split.
The scan
hardened:scan runs when scan = true. It scans the CycloneDX SBOM produced by
hardened:sbom — not a re-derived inventory — so the crates, modules, gems, and
wheels folded into the SBOM (see SBOMs) are all in scope:
$ grype "sbom:sbom-<artifact-name>.cdx.json" -o json > grype.json
Scanning the SBOM (rather than the image) is what makes ecosystem-dependency CVEs matchable at all — a closure-only scan would miss them.
OpenVEX exceptions
Not every reported CVE actually affects your build. A vulnerability might be in
a code path you don’t compile, or already mitigated. OpenVEX
(Vulnerability Exploitability eXchange) lets you record, as signed data, that a
specific CVE is not_affected for this artifact — so the gate doesn’t block on
it (ADR-0014).
You ship your exceptions in your own .openvex/ directory, the same way this
repo does. Each exception is a deliberate, reviewed statement, not a blanket
mute — it names the CVE and the justification. A CVE with no exception is
treated as live.
The scan → gate split
Scanning and gating are deliberately two concerns (ADR-0033):
- Scan produces the full Grype report (
grype.json, kept as an artifactwhen: always) — the complete picture, exceptions and all. - Gate is the pass/fail decision: after VEX exceptions are applied, if any Critical finding remains, the job exits non-zero and the pipeline fails.
Keeping them separate means you always have the full report to triage from, even on a failed pipeline, and the gate’s yes/no is a clean, auditable step rather than buried in scan output.
CRIT=$(jq '[.matches[] | select(.vulnerability.severity=="Critical")] | length' grype.json)
# CRIT > 0 ⇒ gate FAILS
Adding an exception
When the gate flags a Critical you’ve determined is not applicable, add an
OpenVEX statement to your .openvex/ directory with the CVE ID and a
justification, and re-run. The scan still reports it; the gate no longer blocks
on it. Treat this as a reviewed decision — an exception is an assertion you’re
standing behind, per this project’s allowlisting discipline.
Reference
OpenVEX-for-Nix-backported-CVEs is ADR-0014; the scan/gate split (and the provenance/dashboard split alongside it) is ADR-0033.