Repository: google/osv-scanner
Pull request #492 (2023-08-17 19:39:27)

fix: ensure that "introduced 0" events are sorted before any other event
Part of #491


Patch:
diff --git a/pkg/models/vulnerability.go b/pkg/models/vulnerability.go
index e92d423..1d92217 100644
--- a/pkg/models/vulnerability.go
+++ b/pkg/models/vulnerability.go
@@ -207,7 +207,18 @@ func (ar Range) containsVersion(pkg lockfile.PackageDetails) bool {
 	vp := semantic.MustParse(pkg.Version, pkg.CompareAs)
 
 	sort.Slice(ar.Events, func(i, j int) bool {
-		return semantic.MustParse(ar.Events[i].version(), pkg.CompareAs).CompareStr(ar.Events[j].version()) < 0
+		a := ar.Events[i]
+		b := ar.Events[j]
+
+		if a.Introduced == "0" {
+			return true
+		}
+
+		if b.Introduced == "0" {
+			return false
+		}
+
+		return semantic.MustParse(a.version(), pkg.CompareAs).CompareStr(b.version()) < 0
 	})
 
 	var affected bool


Test patch:
diff --git a/pkg/models/vulnerability_test.go b/pkg/models/vulnerability_test.go
index 14a3992..1303e07 100644
--- a/pkg/models/vulnerability_test.go
+++ b/pkg/models/vulnerability_test.go
@@ -593,6 +593,41 @@ func TestOSV_IsAffected_AffectsWithEcosystem_Unsorted(t *testing.T) {
 
 	// an empty version should always be treated as affected
 	expectIsAffected(t, vuln, "", true)
+
+	// zeros with build strings
+	vuln = buildOSVWithAffected(
+		models.Affected{
+			// golang.org/x/sys
+			Package: models.Package{Ecosystem: models.EcosystemNPM, Name: "my-package"},
+			Ranges: []models.Range{
+				buildEcosystemAffectsRange(
+					models.Event{Fixed: "0.0.0-20220412211240-33da011f77ad"},
+					models.Event{Introduced: "0"},
+				),
+			},
+		},
+		models.Affected{
+			// golang.org/x/net
+			Package: models.Package{Ecosystem: models.EcosystemNPM, Name: "my-package"},
+			Ranges: []models.Range{
+				buildEcosystemAffectsRange(
+					models.Event{Introduced: "0.0.0-20180925071336-cf3bd585ca2a"},
+					models.Event{Fixed: "0"},
+				),
+			},
+		},
+	)
+
+	for _, v := range []string{"0.0.0", "0.14.0"} {
+		expectIsAffected(t, vuln, v, false)
+	}
+
+	for _, v := range []string{"0.0.0-20180925071336-cf3bd585ca2a"} {
+		expectIsAffected(t, vuln, v, true)
+	}
+
+	// an empty version should always be treated as affected
+	expectIsAffected(t, vuln, "", true)
 }
 
 func TestOSV_IsAffected_AffectsWithSemver_DifferentEcosystem(t *testing.T) {
@@ -835,6 +870,44 @@ func TestOSV_IsAffected_AffectsWithSemver_Unsorted(t *testing.T) {
 
 	// an empty version should always be treated as affected
 	expectIsAffected(t, vuln, "", true)
+
+	// an empty version should always be treated as affected
+	expectIsAffected(t, vuln, "", true)
+
+	// zeros with build strings
+	vuln = buildOSVWithAffected(
+		models.Affected{
+			// golang.org/x/sys
+			Package: models.Package{Ecosystem: models.EcosystemNPM, Name: "my-package"},
+			Ranges: []models.Range{
+				buildSemverAffectsRange(
+					models.Event{Fixed: "0.0.0-20220412211240-33da011f77ad"},
+					models.Event{Introduced: "0"},
+				),
+			},
+		},
+		models.Affected{
+			// golang.org/x/net
+			Package: models.Package{Ecosystem: models.EcosystemNPM, Name: "my-package"},
+			Ranges: []models.Range{
+				buildSemverAffectsRange(
+					models.Event{Introduced: "0.0.0-20180925071336-cf3bd585ca2a"},
+					models.Event{Fixed: "0"},
+				),
+			},
+		},
+	)
+
+	for _, v := range []string{"0.0.0", "0.14.0"} {
+		expectIsAffected(t, vuln, v, false)
+	}
+
+	for _, v := range []string{"0.0.0-20180925071336-cf3bd585ca2a"} {
+		expectIsAffected(t, vuln, v, true)
+	}
+
+	// an empty version should always be treated as affected
+	expectIsAffected(t, vuln, "", true)
 }
 
 func TestOSV_IsAffected_OnlyVersions(t *testing.T) {