feat(extract/mitre/cve/v5): extract SSVC from CNA/ADP metrics#862
Merged
Conversation
MaineK00n
force-pushed
the
MaineK00n/extract-mitre-cve-v5-ssvc
branch
from
June 24, 2026 10:29
6909862 to
fe27f2e
Compare
MaineK00n
force-pushed
the
MaineK00n/extract-mitre-cve-v5-ssvc
branch
3 times, most recently
from
June 25, 2026 06:58
6bfb569 to
062b622
Compare
MaineK00n
marked this pull request as ready for review
June 25, 2026 07:49
Contributor
There was a problem hiding this comment.
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 anSSVC []ssvc.SSVCfield tovulnerability/content.Contentwith deterministicSort()/Compare(). - Extend the MITRE CVE v5 extractor to read
metric.otherentries wheretype == "ssvc"from CNA + ADP containers and emit them tagged with the provider source label. - Publish an
optional.container_typesmap (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. |
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
force-pushed
the
MaineK00n/extract-mitre-cve-v5-ssvc
branch
from
June 25, 2026 09:41
062b622 to
8c3dae4
Compare
This was referenced Jun 25, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Extract SSVC from MITRE CVE v5 records and record the CNA/ADP container role for every source label.
pkg/extract/types/data/ssvctype (Source,Role,Version,Options []{Key,Value},Timestamp) withSort()/Compare().SSVC []ssvc.SSVCfield onvulnerability/content.Content(Sort()/Compare()updated).extract/mitre/cve/v5readsmetric.otherentries wheretype == "ssvc"from the CNA container and each ADP container, tagging every entry with its provider source label.optional.container_typesmap (source label -> "CNA"/"ADP") so a consumer can tell which container any source label (in severity/cwe/references/ssvc/...) came from.Example output:
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:
metric.other.MitreContainer.ContainerType("CNA"/"ADP") assigned from the container's structural position (containers.cnavscontainers.adp[]) — never from a-ADPshortName suffix (which is only a CISA naming convention and is not schema-guaranteed). This PR reproduces that behavior structurally and exposes it viaoptional.container_types, leaving the sharedsourcestring fields untouched.How
other:ssvcmetric, marshal/unmarshal thecontentinto a focused struct and normalize each decision point to a{key, value}option. Timestamp parsed with RFC3339Nano.container_typesmap from structural position while iterating the CNA/ADP containers.Testing
GOEXPERIMENT=jsonv2 go test ./...passes.Comparetable tests for the newssvctype.ssvcblocks and theoptional.container_typesmap on the published CVEs (the REJECTED fixture is unchanged).Note
vulnerability/content.Contentis imported byvuls2andfilter-vuls-data-extracted-redhat. The newSSVCfield is additive (backward-compatible) and the container role is carried in the existingOptionalmap, so no sharedsourcetypes 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