v0.18.0 — Vulnerability SLA tracking, regulatory SBOM conformance, upgrade clustering
A feature release — the first since v0.14.0, so it carries the whole
development cycle behind it. Everything here is additive and
backward-compatible; read the upgrade notes below for the new forward-only
migrations and the changed defaults. The full machine-readable changelog lives
in CHANGELOG.md.
Highlights
A remediation clock that survives re-scans — vulnerability SLA / aging
Findings now carry a project-level first-detection timestamp
(first_detected_at) that persists across re-scans, re-matches, and container
re-scans — the remediation clock no longer resets every scan. Severity-based
SLA due dates ride on top of it (VULN_SLA_DAYS_CRITICAL/HIGH/MEDIUM/LOW,
defaults 7 / 30 / 90 / 180 days; info and unknown severities carry no SLA),
served on the vulnerability list and detail APIs as first_detected_at /
sla_due_date / sla_status (overdue · imminent · ok), with an sla= filter
and sort=sla_due. The Vulnerabilities tab gains an "SLA due" column, an inline
SLA filter, and a drawer chip with the first-detected line. A daily sweep
(trustedoss.vuln_sla_sweep, VULN_SLA_ALERTS_ENABLED, on by default) notifies
the owning team once per project when open findings cross their due date
(notification kind vuln_sla_breach, per-user preferences respected). This
closes the aging / "remediate without undue delay" gap the CRA compliance
mapping had to flag as a limitation. See
Remediation SLA and aging.
SBOM conformance now speaks to regulators — field checks + crosswalk
Uploaded-SBOM conformance scoring gains five advisory per-component field checks
named by the regulatory baselines (BSI TR-03183-2 for the EU Cyber Resilience
Act, the NTIA minimum elements): SHA-512 checksum, component creator, component
filename, source / distribution URI, and delivered-file properties coverage.
They are verdict-neutral — they describe how well an SBOM would answer a
regulator and never move the pass / warn / fail badge
(SBOM_CONFORMANCE_FIELD_MIN_PCT, default 80, tunes the coverage bar). The
conformance response and panel add a regulatory crosswalk: per-framework rollups
(BSI TR-03183-2, NTIA, EU AI Act Annex IV, the Korean AI Framework Act) showing
which mapped requirements are present, a gap, or human-review-only — a
documentation-preparation aid with a vendored disclaimer, not a compliance
determination. Coverage checks also stop failing zero-package SBOMs, and dataset
(type: "data") components no longer count against package-only fields such as
PURL coverage. See
Regulatory crosswalk
and the CRA compliance mapping.
Version currency — components behind the latest patch
A sibling of the EOL flag, answering a different question: not "is this release
line dead?" but "is this version behind the newest patch of its still-supported
release line?". It reuses the vendored endoflife.date snapshot (each cycle
carries its newest patch), so it stays fully offline — no new network at scan
time. Components in the Components tab and drawer gain an "Outdated" badge (a
lower-urgency amber-below tone than EOL) with the latest patch version, an
"Outdated only" filter (?outdated=true), and a project-Overview "N outdated"
chip. See Version currency.
"Group by upgrade" — the remediation worklist
The project Vulnerabilities tab gains a Flat ⇄ By upgrade toggle. "By upgrade"
replaces the flat finding list with the whole-project set of remediation
clusters — each the minimum safe upgrade for one component (the semver-maximum
of its open findings' fix versions), showing Upgrade {component} {from} → {to}
and how many findings it resolves, expandable to the findings themselves.
Components whose open findings have no published fix are grouped under "No
upgrade available" rather than given a misleading partial bump. Served by
GET /v1/projects/{id}/vulnerabilities/upgrade-clusters, which reuses the build
gate's own open-status set, so the cluster counts stay in lock-step with the
gate. See Group by upgrade.
Container scans surface base-image OS end-of-life (EOSL)
Trivy now reports whether a scanned image's base OS release is past its end-of-service-life — it no longer receives upstream security fixes, so newly disclosed CVEs will never be patched on it, a risk that no individual package CVE captures. TRUSCA persists that OS family/release and EOSL flag and shows an "OS end-of-life" panel on the scan detail page when the release is EOL. The verdict comes from Trivy's bundled database (no extra network), so a stale database may not yet flag a recently retired release. See Base-image OS end-of-life.
License coverage: RubyGems and NuGet, plus Korean license content
License enrichment now covers RubyGems (rubygems.org) and NuGet
(api.nuget.org), joining the existing PyPI / Maven / crates.io / pkg.go.dev
fetchers — Ruby and .NET dependencies with a bare manifest are no longer 100%
unknown. The lookup is now gated on LICENSE_FETCH_ENABLED (default on —
only a package name and version leave the network) so an air-gapped deployment
can set it false to skip the fetch cleanly. Separately, when the interface
language is Korean, each classification-catalog license's plain-language summary
and obligation text render in Korean, with the authoritative English original
one click away (covering the 52-license catalog; licenses outside it fall back
to English). See
the components and licenses guide.
Policy-aware SBOM export profiles
GET /v1/projects/{id}/sbom accepts an optional profile. policy-annotated
flags each component that violates the project's effective license policy in
place (CycloneDX properties / SPDX annotations, for forbidden and conditional
licenses); policy-filtered drops forbidden components — and the vulnerability
entries referencing them — recording the excluded count on the document. The
default export is unchanged and byte-stable. Profile exports are not
cosign-signed — the signature covers only the canonical default SBOM. See
Policy profiles.
Documentation — Wave 7 parity
New pages, EN + KO: a Triage guide that consolidates how a finding flows across VEX vulnerability triage, component approval, and the build gate — and makes explicit that a rejected component approval does not gate the build; an Analysis types reference matrix of source SBOM scan / container scan / policy gate / (planned) reachability; a Best practices category (scan frequency, policy design, team structure, upgrade cadence); and an FAQ link hub.
Fixes
- Dynamic-scan sidecar now targets the git-clone root. With
SCAN_EXECUTOR=local_docker, an Android scan of a git repository routed to the sidecar but read the compileSdk and ran the build from the outer workspace directory instead of the clone root a level below — so it picked the default SDK image and scanned an empty directory. The scan executor now carries the resolved project root and the sidecar uses it. Only affects the opt-inlocal_dockerexecutor; the default in-process path was unaffected.
Upgrade notes
- Migrations auto-apply at container startup (
AUTO_MIGRATE, the default):0040_component_version_currency,0041_vulnerability_first_detected, and0042_notification_kind_vuln_sla_breachare forward-only. - SLA tracking is on by default with 7 / 30 / 90 / 180-day windows. Existing
open findings begin their clock at their first post-upgrade re-scan; tune the
windows with
VULN_SLA_DAYS_*and turn breach alerts off withVULN_SLA_ALERTS_ENABLED=false. - License enrichment egress is now gated. The registry lookup previously ran
unconditionally; it now respects
LICENSE_FETCH_ENABLED(default on). An air-gapped deployment should set itfalseto skip the fetch cleanly. - The regulatory field checks and crosswalk are advisory — they never change a stored pass / warn / fail verdict, and earlier scans pick up mapping updates at read time without a re-scan.
Pull the 0.18.0 images (or helm upgrade to the 0.18.0 image tag).