fix(frameworks): match cve entries against a bare-major version (#320)

drupal's generator meta only exposes a bare major, so the extracted
version is "10"/"9". versionAffected only matched when the affected
entry was a component-prefix of the version, never the reverse, so a
bare major never matched a dotted affected entry and every drupal cve
was silently missed. match on dotted boundaries in either direction.
This commit is contained in:
Tigah
2026-07-22 12:51:48 -07:00
committed by GitHub
parent 5ebeb89f93
commit fa84b3f7a5
2 changed files with 27 additions and 3 deletions
@@ -65,6 +65,18 @@ func TestResolveVersionFeedsCVELookup(t *testing.T) {
}
}
// Drupal's generator meta only exposes a bare major, so the extracted version
// is "10"/"9". the cve lookup must still surface the matching CVE instead of
// missing it because the affected entries are dotted.
func TestGetVulnerabilitiesBareMajor(t *testing.T) {
if cves, _ := getVulnerabilities("Drupal", "10"); len(cves) == 0 {
t.Error("expected Drupal 10 to surface CVE-2023-44487, got none")
}
if cves, _ := getVulnerabilities("Drupal", "9"); len(cves) == 0 {
t.Error("expected Drupal 9 to surface CVE-2023-44487, got none")
}
}
func TestVersionAffected(t *testing.T) {
tests := []struct {
version string
@@ -77,6 +89,13 @@ func TestVersionAffected(t *testing.T) {
{"4.20", "4.2", false}, // the boundary bug: 4.20 is not a 4.2.x release
{"4.20.0", "4.2", false},
{"5.0", "4.2", false},
// a coarser version covers the listed sub-versions: Drupal's generator
// only emits a bare major, which must still match its dotted entries.
{"10", "10.0", true},
{"9", "9.3", true},
// coarser matching stays on dotted boundaries: "1" is not "10.x".
{"1", "10.0", false},
{"10", "100.0", false},
}
for _, tt := range tests {
+8 -3
View File
@@ -219,8 +219,13 @@ func getVulnerabilities(framework, version string) ([]string, []string) {
}
// versionAffected reports whether version falls under an affected-version
// entry. the entry is a version prefix, matched only on dotted boundaries, so
// "4.2" covers 4.2 and 4.2.1 but not 4.20.
// entry. matching is on dotted component boundaries in either direction, so
// "4.2" covers 4.2 and 4.2.1 but not 4.20, and a coarser version covers the
// listed sub-versions. the latter matters because some detectors only recover
// a bare major (Drupal's generator emits "10"); without it a bare major never
// matches a dotted affected entry and the CVE is silently missed.
func versionAffected(version, affected string) bool {
return version == affected || strings.HasPrefix(version, affected+".")
return version == affected ||
strings.HasPrefix(version, affected+".") ||
strings.HasPrefix(affected, version+".")
}