feat(detector): route Fortinet to vuls2#2591
Merged
Merged
Conversation
Mirror the Cisco / Palo Alto migrations: move Fortinet CPE detection from go-cve-dictionary to the vuls2 path. Fortinet now comes from the two new extractors — fortinet-cvrf (merged) and fortinet-csaf (MaineK00n/vuls-data-update #853) — both rooted on the FG-IR PSIRT advisory. - detector.go: drop Fortinet from the go-cve-dictionary admission gate and the FillCvesWithGoCVEDictionary CveContent fill, remove the DistroAdvisory synthesis, and nil detail.Fortinets before confidence selection (same as NVD / Cisco / Palo Alto). - vuls2/vendor.go: extend every Fortinet source switch (toCveContentType, toVuls0Confidence x2, advisoryReference, compareSourceID) to cover FortinetCVRF and FortinetCSAF, with CSAF preferred over CVRF in compareSourceID (tier 5 vs 4, like the Cisco/Palo Alto CSAF>CVRF/JSON order). cveContentSourceLink gains a models.Fortinet case returning the PSIRT advisory page keyed by the root ID (FG-IR-...), matching advisoryReference. Fortinet is advisory-rooted like Cisco. The CVRF stub is bare (sparse CveContent + DistroAdvisory); the CSAF stub is rich (CVSS/CWE/refs), so the generic path builds a full CveContent. Either way the advisory carries no vendor SIR (Fortinet severity is CVSS), so DistroAdvisory.Severity is empty. No enrich. Bumps vuls-data-update to MaineK00n/vuls-data-update#853 head (3263815) for the FortinetCSAF source id and the fortinet-* cpecriterion RangeTypes; keeps the pan-os RangeType from the Palo Alto work. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…op untested bare Fortinet - Add a CVRF-only postConvert case: a bare vulnerability stub yields a sparse Fortinet CveContent (no CVSS) plus a DistroAdvisory, source link to the PSIRT advisory (root id), DistroAdvisory.Severity empty (advisory CVSS, not vendor). - Add a csaf+cvrf both-detect case: the same FG-IR advisory / CVE is detected by both sources and merges to the csaf-preferred result — csaf scalars (title / summary / CVSS) win, the DistroAdvisory takes csaf's (later Updated), and vuls2-sources lists both. Verifies the compareSourceID CSAF > CVRF ordering. - Drop the bare sourceTypes.Fortinet from the source switches: only FortinetCVRF / FortinetCSAF are produced into the vuls2 DB and exercised by tests; the legacy "fortinet" source id is no longer routed. Built the real extracted data (vuls-data-update extract fortinet-cvrf/csaf from the GHCR raw) to model these on FG-IR-25-032 / CVE-2025-54838. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
d042419 to
ac7ef71
Compare
…veContents Confirm that a CVE detected by both NVD (feed v2) and Fortinet CSAF retains both CveContents in the merged result: models.Nvd and models.Fortinet are distinct CveContentTypes, so mergeVulnInfo keys them separately and neither overwrites the other (and both confidences are kept). Distinct from the csaf+cvrf case, where the two contents share models.Fortinet and merge into one. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…saf versions MaineK00n/vuls2#396 ("bump vuls-data-update to nightly (fortinet csaf extractor)") is merged, so drop the PR-head pins and use the released nightly commits: - github.com/MaineK00n/vuls2 -> v0.0.1-alpha.0.20260630120316-69ab575c2ebe - github.com/MaineK00n/vuls-data-update -> v0.0.0-20260630113343-f3c7f13ad814 (pulls in github.com/vulsio/go-fortinet-version, the fortinet-* RangeType backend) This replaces the temporary vuls-data-update#853-head pin now that the Fortinet CSAF extractor and range types have landed. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
shino
added a commit
to vulsio/vuls-data-db
that referenced
this pull request
Jun 30, 2026
* ci(db): add fortinet-cvrf + fortinet-csaf (nightly active, main commented) Add the two new Fortinet extractors to the DB build, both rooted on the FG-IR PSIRT advisory: - db-nightly.mk: enable fortinet-cvrf and fortinet-csaf so the nightly DB carries Fortinet detection criteria. - db-main.mk: add them commented out — keep the production main (:0/:latest) DB unchanged until vuls is ready to consume them. Required for vuls's Fortinet CPE detection once it routes Fortinet through vuls2 (future-architect/vuls#2591). Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> * ci: wire fortinet-cvrf + fortinet-csaf through extract/backup/gc/restore/truncate The db-add lines alone are not enough — a new extracted source must also be listed in the surrounding CI workflows (mirrors the paloalto wiring in #182). The raw side (fetch-fortinet-csaf/cvrf, raw backup/gc/archive/restore) was already wired, so this only adds the extract/extracted side: - extract-all.yml / extract-main.yml: uncomment fortinet-csaf and fortinet-cvrf (fortinet-handmade stays commented). - backup-daily/monthly/weekly.yml, gc.yml, restore-all.yml, truncate.yml: add vuls-data-extracted-fortinet-csaf / -cvrf to the extracted matrices. - gc-extracted.yml: add the two extracted tags with the standard pack settings. - truncate-extracted.yml: add the bare fortinet-csaf / fortinet-cvrf names. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> * ci(archive-raw): add missing "fortinet" raw source archive-raw.yml listed fortinet-csaf and fortinet-cvrf but not the bare "fortinet" raw source, which every other raw workflow (archive, gc, gc-raw, backup-*, restore-all) already includes. Add it for consistency. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> * ci(db): order fortinet-csaf before fortinet-cvrf for consistency Match the csaf-then-cvrf ordering used by the workflow / backup / gc / truncate lists in this PR (and alphabetical), so the db-add lists stay easy to diff and keep in sync. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
Pull request overview
Routes Fortinet CPE-based detection away from go-cve-dictionary and into the vuls2 detection pipeline, aligning Fortinet with the prior Cisco/Palo Alto migrations and enabling Fortinet CVRF/CSAF-backed CPE criteria and source-linking.
Changes:
- Stop admitting/filling Fortinet data via go-cve-dictionary (detection gate + Fortinet CveContent fill removed; Fortinet details nilled before confidence selection).
- Add/extend vuls2 vendor/source mappings for Fortinet CVRF + CSAF (content type/confidence mapping, source preference ordering, PSIRT advisory source links).
- Add vuls2 postConvert test coverage for Fortinet CSAF/CVRF behavior and merging semantics; bump vuls-data-update/vuls2 deps accordingly.
Reviewed changes
Copilot reviewed 4 out of 5 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| go.mod | Bumps vuls-data-update/vuls2 and adds an indirect Fortinet version lib dependency. |
| go.sum | Updates checksums for the dependency bumps and new indirect dependency. |
| detector/detector.go | Removes Fortinet go-cve-dictionary fill and Fortinet-only admission; nils Fortinet details before confidence selection. |
| detector/vuls2/vendor.go | Adds Fortinet CVRF/CSAF source handling (reference/source link, confidence mapping, source preference). |
| detector/vuls2/vuls2_test.go | Adds Fortinet-focused postConvert tests for CSAF/CVRF detection and merge behavior. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
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
Move Fortinet CPE detection from go-cve-dictionary to the vuls2 path, mirroring the Cisco (#2581) and Palo Alto (#2589) migrations. Fortinet now comes from the two extractors —
fortinet-cvrfandfortinet-csaf— both rooted on the FG-IR PSIRT advisory.Note
Detection requires both
fortinet-cvrfandfortinet-csafin the vuls2 DB — wired in vulsio/vuls-data-db#187 (nightly active;db-main.mkstays commented until this PR ships, so:0/:latestconsumers aren't fed Fortinet ranges before vuls can parse them).How
Detection
detectCpeURIsCvesWithGoCVEDictionarydrops Fortinet from the admission gate and nilsdetail.Fortinetsbefore confidence selection (same treatment as NVD / Cisco / Palo Alto); the go-cve-dictionary FortinetDistroAdvisorysynthesis is removed.FillCvesWithGoCVEDictionaryno longer fills FortinetCveContent.walkVulnerabilityDatasis unchanged: Fortinet is detected like any other CPE source. Fortinet is advisory-rooted (root = FG-IR PSIRT advisory). The CVRF stub is bare → sparseCveContent+DistroAdvisory; the CSAF stub is rich (CVSS/CWE/refs) → fullCveContent. Either way the advisory carries no vendor SIR (Fortinet severity is CVSS), soDistroAdvisory.Severityis empty.toCveContentType,toVuls0Confidence×2,advisoryReference,compareSourceID) coversFortinetCVRFandFortinetCSAF. The legacy barefortinetsource id is intentionally not routed (not produced into the vuls2 DB). CSAF is preferred over CVRF incompareSourceID(tier 5 vs 4, matching the Cisco/Palo Alto CSAF > CVRF/JSON ordering), so when both detect the same CVE the CSAF content wins the merge.cveContentSourceLinkgains amodels.Fortinetcase returninghttps://www.fortiguard.com/psirt/<FG-IR-...>(keyed by the root ID), matchingadvisoryReference.Enrich
Dependency bump
v0.0.1-alpha.0.20260630120316-69ab575c2ebe, vuls-data-update →v0.0.0-20260630113343-f3c7f13ad814(post chore(deps): bump vuls-data-update to nightly, for fortinet MaineK00n/vuls2#396, which bumped vuls-data-update to the merged Fortinet CSAF extractor). This pulls ingithub.com/vulsio/go-fortinet-version, the backend for thefortinet-*cpecriterionRangeTypes, and retains thepan-osRangeType from feat(detector): route Palo Alto to vuls2 #2589. Required both for the feature and for vuls0 to read any vuls2 DB that contains Fortinet (the old vuls2 fails on thefortinet-*ranges /unsupported source: fortinet-cvrf).Testing
postConvertunit tests cover: CSAF (richCveContentwith CVSS/CWE/refs, PSIRT source link, empty-SeverityDistroAdvisory,fortinet-fortipamrange); CVRF (bare stub → sparseCveContent+DistroAdvisory); CSAF + CVRF both detecting the same CVE (CSAF preferred in the merge); and NVD-v2 + Fortinet-CSAF coexistence (bothCveContents kept, since they are distinctCveContentTypes). Fixtures model realFG-IR-25-032/FG-IR-24-041.GOWORK=off go test ./detector/...green; golangci-lint clean.fortinet-cvrf+fortinet-csafdb-added: 137 CVEs in common, OLD=138 / NEW=141. The 1 OLD-only is a go-cve vendor:product over-match (scanned version outside the affected range; vuls2 correctly excludes it); the 4 NEW-only are go-cve data gaps (missing product coverage / missing CVE) that vuls2 version-confirms. No regressions — vuls2 Fortinet detection is at parity or better. (The fullmaster-binary harness can't run the OLD side here becausemastercan't read a Fortinet-containing vuls2 DB — which is exactly the dependency this PR resolves.)🤖 Generated with Claude Code