diff --git a/grype/matcher/golang/matcher_test.go b/grype/matcher/golang/matcher_test.go index c9b3d417e3a..1b4498027d9 100644 --- a/grype/matcher/golang/matcher_test.go +++ b/grype/matcher/golang/matcher_test.go @@ -183,7 +183,7 @@ func (mp *mockProvider) populateData() { // for TestMatcher_DropMainPackageIfNoVersion "istio.io/istio": { { - Constraint: version.MustGetConstraint("< 5.0.7", version.UnknownFormat), + Constraint: version.MustGetConstraint("< v0.0.0-20230606222826-f59ce19ec6b6", version.UnknownFormat), ID: "CVE-2013-fake-BAD", }, }, diff --git a/grype/search/only_qualified_packages.go b/grype/search/only_qualified_packages.go index 9fbd2c3f4f3..875f67acb12 100644 --- a/grype/search/only_qualified_packages.go +++ b/grype/search/only_qualified_packages.go @@ -16,7 +16,6 @@ func onlyQualifiedPackages(d *distro.Distro, p pkg.Package, allVulns []vulnerabi for _, q := range vuln.PackageQualifiers { v, err := q.Satisfied(d, p) - if err != nil { return nil, fmt.Errorf("failed to check package qualifier=%q for distro=%q package=%q: %w", q, d, p, err) } diff --git a/grype/version/golang_constraint.go b/grype/version/golang_constraint.go index b0fdda9d3d8..0f966ef3a5b 100644 --- a/grype/version/golang_constraint.go +++ b/grype/version/golang_constraint.go @@ -1,6 +1,10 @@ package version -import "fmt" +import ( + "fmt" + "regexp" + "strings" +) var _ Constraint = (*golangConstraint)(nil) @@ -31,9 +35,37 @@ func (g golangConstraint) Satisfied(version *Version) (bool, error) { if g.raw == "" { return true, nil // the empty constraint is always satisfied } + + var constraintContainsPseudoVersion bool + for _, units := range g.expression.units { + for _, unit := range units { + if isPseudoVersion(unit.version) { + constraintContainsPseudoVersion = true + break + } + } + } + // when we get a pseudo version from a package, and the constraint being compared against is not a pseudo version, + // we should not consider it as satisfied + // ex: constraint of type ">=v1.0.0", should not be compared to version = "v0.0.0-0.20210101000000-abcdef123456" + if isPseudoVersion(version.String()) && !constraintContainsPseudoVersion { + return false, nil + } + return g.expression.satisfied(version) } +// PseudoVersionPattern is a regular expression pattern to match pseudo versions +const pseudoVersionPattern = `^v0\.0\.0[-+].*$` + +var pseudoVersionRegex = regexp.MustCompile(pseudoVersionPattern) + +// Check if a version string is a pseudo version +func isPseudoVersion(version string) bool { + // List of prefixes commonly used for pseudo versions + return pseudoVersionRegex.MatchString(strings.TrimSpace(version)) +} + func newGolangComparator(unit constraintUnit) (Comparator, error) { ver, err := newGolangVersion(unit.version) if err != nil { diff --git a/grype/version/golang_constraint_test.go b/grype/version/golang_constraint_test.go index 4a73767af01..92fae692eb5 100644 --- a/grype/version/golang_constraint_test.go +++ b/grype/version/golang_constraint_test.go @@ -38,6 +38,19 @@ func TestGolangConstraints(t *testing.T) { constraint: "", satisfied: true, }, + { + name: "pseudo version from package should not be considered as satisfied against semver constraint", + version: "v0.0.0-0.20210101000000-abcdef123456", + constraint: "