Skip to content

feat(detector/vuls2): flatten CPE AND conjunctions to OR in vuls0#2606

Merged
MaineK00n merged 5 commits into
masterfrom
MaineK00n/vuls2-flatten-cpe-and-conjunction
Jul 15, 2026
Merged

feat(detector/vuls2): flatten CPE AND conjunctions to OR in vuls0#2606
MaineK00n merged 5 commits into
masterfrom
MaineK00n/vuls2-flatten-cpe-and-conjunction

Conversation

@MaineK00n

Copy link
Copy Markdown
Collaborator

What

vuls2's CPE walk (walkCPECriteria in detector/vuls2/vuls2.go) respected NVD AND applicability nodes, requiring every vulnerable=true leg to have a matching scanned CPE. This PR folds AND identically to OR in the CPE walk, so any single satisfied leg carries the node.

Why

go-cve-dictionary flattens every vulnerable=true CPE in an applicability node into an independently matchable OR list, ignoring the AND/OR operator, and existing users relied on that behaviour.

The two backends diverged on CVE-2021-28039, whose NVD config is linux_kernel (x86, 5.9–5.11.3) AND xen:xen — both marked vulnerable=true:

AND
├─ linux_kernel:*:x86 (5.9.0–5.11.3)  vulnerable:true  → 5.10.0 matches ✓
└─ xen:xen:-                          vulnerable:true  → not scanned    ✗  → AND vetoed

A kernel-only scan matched the kernel leg but not the (absent) Xen leg, so the AND vetoed the match and vuls2 under-reported relative to go-cve-dictionary. NVD marking the Xen environment vulnerable=true (rather than as a vulnerable=false guard, which pruneCPECriteria already strips) is what tripped vuls2's stricter AND handling.

How

  • walkCPECriteria's walk now folds AND the same as OR: any single satisfied leg carries the node and contributes its matches at its own confidence tier. The conjunction-demotion of exact→vendor:product is dropped (there is no conjunction anymore).
  • Scoped to CPE detection (vuls0) only — OS-package detection still uses prunePkgCriteria / Affected and is unaffected.
  • The existing prune pass is unchanged: vulnerable=false environment/hardware guards and non-CPE criterion types are still removed first, so they can neither be matched nor veto.
  • Docstring updated to describe the flatten and its trade-off.

Trade-off

CVEs with a genuine multi-product AND where both products are vulnerable=true will now report each product independently (over-report), matching go-cve-dictionary's long-standing behaviour. This is confined to CPE detection.

Tests

Test_walkCPECriteria and Test_postConvert updated / extended so the AND four-quadrant is covered:

Config Case Expectation
true Accept AND true NotAccept unsatisfied AND detected (flatten)
true Accept AND false NotAccept (guard) AND with vulnerable=false guard detected (prune)
true Accept AND true Accept satisfied AND both detected
true NotAccept AND true NotAccept AND, report nothing not detected

GOEXPERIMENT=jsonv2 go test ./detector/vuls2/ is green; gofmt clean.

🤖 Generated with Claude Code

@MaineK00n MaineK00n self-assigned this Jul 15, 2026
@MaineK00n
MaineK00n marked this pull request as ready for review July 15, 2026 02:19
@MaineK00n
MaineK00n requested a review from Copilot July 15, 2026 02:21

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

This PR changes vuls2’s CPE applicability evaluation (walkCPECriteria) to treat NVD AND nodes the same as OR (flattening), aligning vuls0 CPE detection behavior with go-cve-dictionary and avoiding under-reporting for configurations like CVE-2021-28039.

Changes:

  • Fold AND as OR in walkCPECriteria, removing conjunction-wide tier demotion behavior.
  • Update docstrings/comments to document the flattening trade-off and scope (CPE detection only).
  • Extend/adjust unit tests to cover the ANDOR flatten behavior and related edge cases.

Reviewed changes

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

File Description
detector/vuls2/vuls2.go Implements AND-as-OR folding in the CPE walk and updates the explanatory docstring.
detector/vuls2/vuls2_test.go Updates/adds tests and comments to validate the new flattening behavior for AND nodes.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread detector/vuls2/vuls2.go
Comment thread detector/vuls2/vuls2_test.go Outdated
MaineK00n added a commit that referenced this pull request Jul 15, 2026
…t comment

Address Copilot review on #2606:
- walkCPECriteria's walk now validates c.Operator (AND/OR) and errors on an
  unsupported operator instead of silently taking the OR fold, matching
  walkPkgCriteria's fail-fast behaviour.
- Rewrite the "unsatisfied AND" test comment, which still described the old
  AND-honoured (not-reported) behaviour before contradicting itself with the
  new folded-as-OR (reported) behaviour.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@MaineK00n
MaineK00n requested a review from Copilot July 15, 2026 02:27

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 2 out of 2 changed files in this pull request and generated 1 comment.

Comment thread detector/vuls2/vuls2_test.go Outdated
MaineK00n added a commit that referenced this pull request Jul 15, 2026
Address Copilot review on #2606: the "unsatisfied AND" test comment mixed
"product A"/"product B" prose with "productb leg", which referenced the code's
CPE names inconsistently. Use producta/productb throughout.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@MaineK00n
MaineK00n requested a review from Copilot July 15, 2026 02:46

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 2 out of 2 changed files in this pull request and generated no new comments.

@MaineK00n
MaineK00n requested a review from shino July 15, 2026 02:50

@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 July 15, 2026 18:19
vuls2's CPE walk respected NVD AND applicability nodes, requiring every
vulnerable=true leg to have a matching scanned CPE. go-cve-dictionary
instead flattens every vulnerable=true CPE in a node into an independently
matchable OR list, ignoring the AND/OR operator, and existing users relied
on that behaviour.

This diverged on CVE-2021-28039, whose NVD config is
linux_kernel(x86, 5.9-5.11.3) AND xen:xen -- both marked vulnerable=true.
A kernel-only scan matched the kernel leg but not the (absent) xen leg, so
the AND vetoed the match and vuls2 under-reported relative to gcd.

Fold AND identically to OR in walkCPECriteria: any single satisfied leg
carries the node and contributes its matches at its own tier, so a
co-required product the scan lacks never vetoes the result. The change is
scoped to CPE detection (vuls0) only -- OS-package detection still uses
prunePkgCriteria/Affected and is unaffected. The existing prune pass still
removes vulnerable=false environment/hardware guards so they can neither be
matched nor veto, unchanged.

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

Companion postConvert case to "unsatisfied AND": a vulnerable=true leg that
accepts, AND a vulnerable=false hardware guard that the scan does not
provide. The guard is removed by pruneCPECriteria before the walk, so the
CVE is detected via the satisfied leg. This detected even before the AND->OR
flatten (the guard never survived pruning), which distinguishes it from the
vulnerable=true unsatisfied-leg case that only detects because of the flatten.

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

Adds the AND-shaped counterpart to "cpe no accepted criterion, report
nothing": an AND of two vulnerable=true legs where neither accepts. The
AND->OR flatten finds no satisfied leg, so nothing is reported. This pins
down that folding AND as OR does not spuriously detect when no leg matched --
the negative case the existing AND cases (which all detect) did not cover.

The vulnerable=true-both-accept case is already covered by "satisfied AND".

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

Address Copilot review on #2606:
- walkCPECriteria's walk now validates c.Operator (AND/OR) and errors on an
  unsupported operator instead of silently taking the OR fold, matching
  walkPkgCriteria's fail-fast behaviour.
- Rewrite the "unsatisfied AND" test comment, which still described the old
  AND-honoured (not-reported) behaviour before contradicting itself with the
  new folded-as-OR (reported) behaviour.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Address Copilot review on #2606: the "unsatisfied AND" test comment mixed
"product A"/"product B" prose with "productb leg", which referenced the code's
CPE names inconsistently. Use producta/productb throughout.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@MaineK00n
MaineK00n force-pushed the MaineK00n/vuls2-flatten-cpe-and-conjunction branch from fb93168 to 19ba43b Compare July 15, 2026 09:19
@MaineK00n
MaineK00n merged commit 45714b6 into master Jul 15, 2026
7 checks passed
@MaineK00n
MaineK00n deleted the MaineK00n/vuls2-flatten-cpe-and-conjunction branch July 15, 2026 10:12
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