Skip to main content

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-in local_docker executor; 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, and 0042_notification_kind_vuln_sla_breach are 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 with VULN_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 it false to 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).