Skip to content

feat(detector): route Cisco CPE detection to vuls2 via a unified CveContent pipeline#2587

Closed
shino wants to merge 3 commits into
masterfrom
shino/cpe-detect-cisco-v2
Closed

feat(detector): route Cisco CPE detection to vuls2 via a unified CveContent pipeline#2587
shino wants to merge 3 commits into
masterfrom
shino/cpe-detect-cisco-v2

Conversation

@shino

@shino shino commented Jun 25, 2026

Copy link
Copy Markdown
Collaborator

Supersedes #2581 — a clean re-implementation from master, redesigned to remove the high-entropy that the incremental Cisco-on-NVD approach accumulated. Design docs: docs/cpe-source-routing-redesign.md + -v2.md (lessons + feedback incorporated).

What & why

Migrate Cisco (cisco-json) CPE detection from go-cve-dictionary to the vuls2 boltdb, but first unify how every models.CveContent is built so adding the next advisory-sourced source (JVN/Fortinet/Paloalto) is a one-entry change rather than a 5-switch lockstep edit.

Core lessons baked into the design:

  • provenance (Optional["vuls2-sources"]) can only be attached in the detection path → advisory-sourced content is Detect-built, never delete-then-enrich.
  • content origin (advisory vs vulnerability) is a property of the SourceID, not the CveContentType (cisco-csaf/cvrf/json all map to models.Cisco; only cisco-json is advisory-sourced).
  • CveContent was built in ~5 places with copy-pasted closures → one builder.

Structure (staged, output-neutral first)

commit what neutral?
A toCveContent(cveContentInput, optional) single builder + fromVulnContent/fromDistroAdvisory adapters + flattenCWE/orYear1000; NVD detection/fallback/enrichNVD/enrichRedHatCVE routed through it. CVSS supplied already-computed by caller (never recomputed in the builder), so faithful. ✅ goldens unchanged
B/C contentOrigin + sourcePolicy + policyFor; advisory loop builds an advByID index; vuln loop selects content via one switch policy.origin (+ fromAdvContent). No source advisory-sourced yet. ✅ goldens unchanged
D Cisco on: policyFor(CiscoJSON)=originAdvisory (CISCO/cisco.com, advisory SourceLink); enrichAdvisories backfill; mergeVulnInfo keyed by (type, sourceLink); detector.go gate/strip + retire Cisco gocve fallback. NVD goldens unchanged; Cisco tests added

Verification

  • go build ./..., go test ./detector/... ./models/..., golangci-lint v2.9.0 (CI version) all green.
  • NVD output-neutrality: existing NVD detection/enrich golden tests pass unchanged through A→D.
  • Cisco: ported Test_postConvert (advisory-sourced content with provenance) + Test_enrich cases and the real cisco-json golden fixture pass against the new code.

Remaining (follow-up, not blocking review of the architecture)

  • End-to-end vuls report parity on ~10 real Cisco CPEs (OLD go-cve vs NEW vuls2) — needs a vuls2 DB containing cisco-json (PR feat(extract/cisco/json): add extractor MaineK00n/vuls-data-update#844 extract via db add, or a nightly that includes it).
  • Broader registry facets (gate/strip is currently the concrete NVD-style strip; the v2 design's full SourceID→{type, origin, confidence, gocve-ownership} table + a consistency test) — intentionally lazy per the design.
  • JVN/Fortinet/Paloalto slot in as one policyFor entry each once their content origin is confirmed.

🤖 Generated with Claude Code

shino and others added 3 commits June 25, 2026 13:01
…nt (output-neutral)

Introduce a single CveContent builder, toCveContent(cveContentInput, optional),
fed by a source-neutral projection. Two adapters (fromVulnContent,
fromDistroAdvisory) plus flattenCWE/orYear1000 absorb the CWE-flatten and
year-1000 Published/Modified closures that were copy-pasted across the NVD
detection path, the advisory-only fallback, enrichNVD, and enrichRedHatCVE.

CVSS is supplied already-computed by the caller (toCvss for detection,
enrichCvss for enrich) and never recomputed in the builder, so the refactor is
output-neutral. provenance is the builder's second arg (detection passes
vuls2-sources, enrich passes nil). cveContentSourceLink now takes the CVE-ID
string instead of the vulnerability struct.

No behavior change: existing NVD detection/enrich golden tests pass unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…n (output-neutral)

Add contentOrigin + sourcePolicy + policyFor, and an advByID index built
uniformly in the advisory loop. The vulnerability loop now selects the content
source with a single switch on policyFor(sid).origin: originAdvisory builds one
CveContent per advisory (via the new fromAdvContent adapter), originVulnerability
keeps the stub-plus-advisory-refs behavior.

No source is advisory-sourced yet (policyFor returns originVulnerability for
all), so the originAdvisory branch is dead and behavior is unchanged: NVD
detection/enrich goldens pass. This is the structural seam Cisco plugs into.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Enable Cisco as the first advisory-sourced CPE source on the unified pipeline:

- policyFor(CiscoJSON) returns originAdvisory with the CISCO/cisco.com reference
  tag and the sec.cloudapps.cisco.com advisory SourceLink, so the detection path
  builds Cisco CveContent from the advisory (with vuls2-sources provenance) via
  the shared toCveContent; Cisco carries no CVSS (vendor SIR -> DistroAdvisory).
- enrichAdvisories backfills advisory-sourced content (enrichAdvisoryContent)
  for CVEs detected by other sources, guarded against overwriting detection
  content and attaching no provenance; cisco-json added to the enrich DataSources.
- mergeVulnInfo keys CveContents by (type, source link) so a CVE under multiple
  Cisco advisories keeps all of them; vulnerability-sourced types are unaffected
  (their link is deterministic per CVE).
- detector.go: Cisco dropped from the go-cve-dictionary admission gate and
  content fill, and stripped before getMaxConfidence (mirrors NVD), so Cisco is
  reported solely by vuls2.

NVD detection/enrich goldens unchanged; ported Cisco postConvert/enrich tests
and the real cisco-json fixture pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@shino

shino commented Jun 25, 2026

Copy link
Copy Markdown
Collaborator Author

Approach is nice, but feels like over-engineering

@shino shino closed this Jun 25, 2026
@shino shino deleted the shino/cpe-detect-cisco-v2 branch June 25, 2026 06:19
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.

1 participant