Skip to content

feat(extract/mitre/cve/v5): extract SSVC from CNA/ADP metrics#862

Merged
MaineK00n merged 5 commits into
nightlyfrom
MaineK00n/extract-mitre-cve-v5-ssvc
Jun 25, 2026
Merged

feat(extract/mitre/cve/v5): extract SSVC from CNA/ADP metrics#862
MaineK00n merged 5 commits into
nightlyfrom
MaineK00n/extract-mitre-cve-v5-ssvc

Conversation

@MaineK00n

@MaineK00n MaineK00n commented Jun 24, 2026

Copy link
Copy Markdown
Owner

What

Extract SSVC from MITRE CVE v5 records and record the CNA/ADP container role for every source label.

  • New pkg/extract/types/data/ssvc type (Source, Role, Version, Options []{Key,Value}, Timestamp) with Sort()/Compare().
  • Additive SSVC []ssvc.SSVC field on vulnerability/content.Content (Sort()/Compare() updated).
  • extract/mitre/cve/v5 reads metric.other entries where type == "ssvc" from the CNA container and each ADP container, tagging every entry with its provider source label.
  • The published content now carries an optional.container_types map (source label -> "CNA"/"ADP") so a consumer can tell which container any source label (in severity/cwe/references/ssvc/...) came from.

Example output:

"ssvc": [{
  "source": "CISA-ADP",
  "role": "CISA Coordinator",
  "version": "2.0.3",
  "options": [
    {"key": "Automatable", "value": "no"},
    {"key": "Exploitation", "value": "none"},
    {"key": "Technical Impact", "value": "total"}
  ],
  "timestamp": "2024-05-14T17:28:38.774982Z"
}],
"optional": {
  "container_types": { "CERT-In": "CNA", "CISA-ADP": "ADP" }
}

Why

Migrating from go-cve-dictionary to the vuls2 DB drops SSVC and per-container (CNA/ADP) source labels for enriched MITRE content (see future-architect/vuls#2586). Two gaps:

  • SSVC was not extracted at all — the extractor only looked at the typed CVSS metrics and ignored metric.other.
  • CNA/ADP role was not preserved. go-cve-dictionary recorded this with an explicit MitreContainer.ContainerType ("CNA"/"ADP") assigned from the container's structural position (containers.cna vs containers.adp[]) — never from a -ADP shortName suffix (which is only a CISA naming convention and is not schema-guaranteed). This PR reproduces that behavior structurally and exposes it via optional.container_types, leaving the shared source string fields untouched.

How

  • Group CNA + ADP metrics by provider source (same pattern as Severity/CWE/References).
  • For each other:ssvc metric, marshal/unmarshal the content into a focused struct and normalize each decision point to a {key, value} option. Timestamp parsed with RFC3339Nano.
  • Build the container_types map from structural position while iterating the CNA/ADP containers.

Testing

  • GOEXPERIMENT=jsonv2 go test ./... passes.
  • Added Compare table tests for the new ssvc type.
  • Regenerated golden files; diffs are limited to the new ssvc blocks and the optional.container_types map on the published CVEs (the REJECTED fixture is unchanged).

Note

vulnerability/content.Content is imported by vuls2 and filter-vuls-data-extracted-redhat. The new SSVC field is additive (backward-compatible) and the container role is carried in the existing Optional map, so no shared source types change. Surfacing SSVC / CNA-ADP end-to-end in the vuls2 DB still requires the vuls2 unified content type to consume these fields (future-architect/vuls#2586) — this change only makes them available in the extracted dataset.

🤖 Generated with Claude Code

@MaineK00n
MaineK00n force-pushed the MaineK00n/extract-mitre-cve-v5-ssvc branch from 6909862 to fe27f2e Compare June 24, 2026 10:29
@MaineK00n MaineK00n self-assigned this Jun 24, 2026
@MaineK00n
MaineK00n force-pushed the MaineK00n/extract-mitre-cve-v5-ssvc branch 3 times, most recently from 6bfb569 to 062b622 Compare June 25, 2026 06:58
@MaineK00n
MaineK00n marked this pull request as ready for review June 25, 2026 07:49
Copilot AI review requested due to automatic review settings June 25, 2026 07:50

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds support for carrying SSVC decision data and container role provenance (CNA vs ADP) through the MITRE CVE v5 extraction pipeline, so downstream consumers can preserve SSVC and distinguish per-container source labels when migrating to vuls2 DB.

Changes:

  • Model SSVC as a first-class extracted type (pkg/extract/types/data/ssvc) and add an SSVC []ssvc.SSVC field to vulnerability/content.Content with deterministic Sort()/Compare().
  • Extend the MITRE CVE v5 extractor to read metric.other entries where type == "ssvc" from CNA + ADP containers and emit them tagged with the provider source label.
  • Publish an optional.container_types map (source label → "CNA"/"ADP") and update golden outputs accordingly.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
pkg/fetch/mitre/cve/v5/types.go Switch some extension/other.content fields to jsontext.Value to retain raw JSON values.
pkg/extract/types/data/vulnerability/content/content.go Add SSVC field and include it in Sort()/Compare() for deterministic output.
pkg/extract/types/data/ssvc/ssvc.go Introduce SSVC schema type plus Sort()/Compare() for stable ordering.
pkg/extract/types/data/ssvc/ssvc_test.go Unit tests for SSVC Compare.
pkg/extract/mitre/cve/v5/v5.go Extract SSVC from metric.other and add optional.container_types; refactor severity parsing.
pkg/extract/mitre/cve/v5/testdata/golden/data/2024/CVE-2024-6958.json Golden updated to include optional.container_types.
pkg/extract/mitre/cve/v5/testdata/golden/data/2024/CVE-2024-4232.json Golden updated to include ssvc block and optional.container_types.
pkg/extract/mitre/cve/v5/testdata/golden/data/2024/CVE-2024-39565.json Golden updated to include ssvc block and optional.container_types.

Comment thread pkg/extract/mitre/cve/v5/v5.go
Comment thread pkg/extract/mitre/cve/v5/v5.go
Comment thread pkg/extract/mitre/cve/v5/v5.go
Comment thread pkg/extract/mitre/cve/v5/v5.go

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated no new comments.

@MaineK00n
MaineK00n requested a review from shino June 25, 2026 08:19

@shino shino left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🌼

MaineK00n and others added 5 commits June 25, 2026 18:41
Parse the other:ssvc decision-point data from each CNA/ADP metric and
emit it with its provider source label. Adds a new ssvc type and an
additive SSVC field on the vulnerability content.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add an optional container_types map (source label -> "CNA"/"ADP") to the
published content so consumers can tell which container each source label
came from. The role is derived from structural position (containers.cna vs
containers.adp), mirroring how go-cve-dictionary recorded ContainerType,
rather than guessing from any "-ADP" shortName suffix.

Also drop the SSVC id field, which only duplicated the CVE ID.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Type metrics[].other content as jsontext.Value so the fetcher preserves the
raw JSON verbatim instead of round-tripping opaque content through any
(matching mitre/attack and mitre/capec). The extractor then decodes that raw
value straight into the fetch v5.SSVC struct, dropping the intermediate
marshal. The fetch type otherwise stays intact, mirroring the CERT/CC SSVC
computed schema including the optional decision_tree members.

Option values are handled per the schema (string or array of strings) rather
than formatting the raw any, so array-valued selections expand to one option
entry each instead of a Go-formatted "[a b]".

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…alue

x_generator, x_legacyV4Record, x_redhatCweChain, x_affectedList and
x_ConverterErrors are opaque CVE schema extensions the fetcher never
interprets. Preserve them as raw JSON (jsontext.Value) instead of
round-tripping through any, matching the metrics[].other content handling.
The source field is left as any since it is a structured CVE member.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Hoist the severity and ssvc computations out of the content struct literal
so they can propagate errors, and return a wrapped error instead of warning
and skipping when a CVSS vector fails to parse, ssvc content fails to
unmarshal, or an ssvc option value is not a string/array of strings. This
matches how the other extractors (nvd, jvn, enisa, vulncheck, microsoft)
treat unparseable CVSS vectors; mitre/cve/v5 was the lone outlier.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@MaineK00n
MaineK00n force-pushed the MaineK00n/extract-mitre-cve-v5-ssvc branch from 062b622 to 8c3dae4 Compare June 25, 2026 09:41
@MaineK00n
MaineK00n merged commit a278fec into nightly Jun 25, 2026
1 check passed
@MaineK00n
MaineK00n deleted the MaineK00n/extract-mitre-cve-v5-ssvc branch June 25, 2026 09:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants