Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: narrow golang match comparison for pseudo versions #1810

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion grype/matcher/golang/matcher_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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",
},
},
Expand Down
1 change: 0 additions & 1 deletion grype/search/only_qualified_packages.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down
34 changes: 33 additions & 1 deletion grype/version/golang_constraint.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package version

import "fmt"
import (
"fmt"
"regexp"
"strings"
)

var _ Constraint = (*golangConstraint)(nil)

Expand Down Expand Up @@ -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[-+].*$`

// Check if a version string is a pseudo version
func isPseudoVersion(version string) bool {
// List of prefixes commonly used for pseudo versions
regex := regexp.MustCompile(PseudoVersionPattern)
spiffcs marked this conversation as resolved.
Show resolved Hide resolved

return regex.MatchString(strings.TrimSpace(version))
}

func newGolangComparator(unit constraintUnit) (Comparator, error) {
ver, err := newGolangVersion(unit.version)
if err != nil {
Expand Down
13 changes: 13 additions & 0 deletions grype/version/golang_constraint_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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: "<v1.0.0",
satisfied: false,
},
// https://github.com/anchore/grype/pull/1797
{
name: "pseudo version from package should be considered as satisfied against pseudo version constraint",
version: "0.0.0-20230131185645-0ae4915a9391",
constraint: "< 0.0.0-20240131185645-0ae4915a9391",
satisfied: true,
},
}

for _, tc := range tests {
Expand Down
Loading