Skip to content

Commit

Permalink
Merge pull request #124 from anchore/issue-91
Browse files Browse the repository at this point in the history
Explicitly use PythonFormat to address PEP440 rules
  • Loading branch information
Alfredo Deza authored Aug 13, 2020
2 parents 0618d1d + b237bf9 commit 66b2512
Show file tree
Hide file tree
Showing 7 changed files with 34 additions and 7 deletions.
9 changes: 8 additions & 1 deletion grype/version/constraint.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,15 @@ func GetConstraint(constStr string, format Format) (Constraint, error) {
return newDebConstraint(constStr)
case RpmFormat:
return newRpmConstraint(constStr)
case PythonFormat:
// This is specific to PythonFormat so that it adheres to PEP440 and its odd corner-cases
// It is significantly odd enough, that the fuzzyConstraint is the best bet to compare versions.
// Although this will work in most cases, some oddities aren't supported, like:
// 1.0b2.post345.dev456 which is allowed by the spec. In that case (a dev release of a post release)
// the comparator will fail. See https://www.python.org/dev/peps/pep-0440
return newFuzzyConstraint(constStr, "python")
case UnknownFormat:
return newFuzzyConstraint(constStr)
return newFuzzyConstraint(constStr, "unknown")
}
return nil, fmt.Errorf("could not find constraint for given format: %s", format)
}
Expand Down
9 changes: 7 additions & 2 deletions grype/version/format.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const (
SemanticFormat
DebFormat
RpmFormat
PythonFormat
)

type Format int
Expand All @@ -20,12 +21,14 @@ var formatStr = []string{
"Semantic",
"Deb",
"RPM",
"Python",
}

var Formats = []Format{
SemanticFormat,
DebFormat,
RpmFormat,
PythonFormat,
}

func ParseFormat(userStr string) Format {
Expand All @@ -36,6 +39,8 @@ func ParseFormat(userStr string) Format {
return DebFormat
case strings.ToLower(RpmFormat.String()), "rpmdb":
return RpmFormat
case strings.ToLower(PythonFormat.String()), "python":
return PythonFormat
}
return UnknownFormat
}
Expand All @@ -50,9 +55,9 @@ func FormatFromPkgType(t pkg.Type) Format {
case pkg.BundlerPkg:
format = SemanticFormat
case pkg.EggPkg:
format = SemanticFormat
format = PythonFormat
case pkg.WheelPkg:
format = SemanticFormat
format = PythonFormat
default:
format = UnknownFormat
}
Expand Down
7 changes: 6 additions & 1 deletion grype/version/fuzzy_constraint.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,12 @@ var pseudoSemverPattern = regexp.MustCompile(`^(0|[1-9]\d*)(\.(0|[1-9]\d*))?(\.(

type fuzzyConstraint struct {
rawPhrase string
phraseHint string
semanticConstraint *hashiVer.Constraints
constraints constraintExpression
}

func newFuzzyConstraint(phrase string) (*fuzzyConstraint, error) {
func newFuzzyConstraint(phrase, hint string) (*fuzzyConstraint, error) {
constraints, err := newConstraintExpression(phrase, newFuzzyComparator)
if err != nil {
return nil, fmt.Errorf("could not create fuzzy constraint: %+v", err)
Expand All @@ -42,6 +43,7 @@ check:

return &fuzzyConstraint{
rawPhrase: phrase,
phraseHint: hint,
constraints: constraints,
semanticConstraint: semverConstraint,
}, nil
Expand Down Expand Up @@ -74,6 +76,9 @@ func (f *fuzzyConstraint) String() string {
if f.rawPhrase == "" {
return "none (unknown)"
}
if f.phraseHint != "" {
return fmt.Sprintf("%s (%s)", f.rawPhrase, f.phraseHint)
}
return fmt.Sprintf("%s (unknown)", f.rawPhrase)
}

Expand Down
9 changes: 8 additions & 1 deletion grype/version/fuzzy_constraint_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,13 @@ func TestSmartVerCmp(t *testing.T) {
v1, v2 string
ret int
}{
// Python PEP440 crazyness
{"1.5+1", "1.5+1.git.abc123de", -1},
{"1.0.0-post1", "1.0.0-post2", -1},
{"1.0.0", "1.0.0-post1", -1},
{"1.0.0-dev1", "1.0.0-post1", -1},
{"1.0.0-dev2", "1.0.0-post1", -1},
{"1.0.0", "1.0.0-dev1", -1},
{"5", "8", -1},
{"15", "3", 1},
{"4a", "4c", -1},
Expand Down Expand Up @@ -208,7 +215,7 @@ func TestFuzzyConstraintSatisfaction(t *testing.T) {

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
c, err := newFuzzyConstraint(test.constraint)
c, err := newFuzzyConstraint(test.constraint, "")
if err != nil {
t.Fatalf("could not create constraint: %+v", err)
}
Expand Down
3 changes: 3 additions & 0 deletions grype/version/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,9 @@ func (v *Version) populate() error {
ver, err := newRpmVersion(v.Raw)
v.rich.rpmVer = &ver
return err
case PythonFormat:
// use the fuzzy constraint
return nil
case UnknownFormat:
// use the raw string + fuzzy constraint
return nil
Expand Down
2 changes: 1 addition & 1 deletion test/integration/db_mock_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ func NewMockDbStore() *mockStore {
{
ID: "CVE-python-pygments",
VersionConstraint: "< 2.6.2",
VersionFormat: "semver",
VersionFormat: "python",
},
},
},
Expand Down
2 changes: 1 addition & 1 deletion test/integration/match_coverage_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ func addPythonMatches(t *testing.T, theScope scope.Scope, catalog *pkg.Catalog,
Confidence: 1.0,
Vulnerability: *vulnObj,
Package: thePkg,
SearchKey: "language[python] constraint[< 2.6.2 (semver)]",
SearchKey: "language[python] constraint[< 2.6.2 (python)]",
IndirectPackage: nil,
Matcher: match.PythonMatcher,
})
Expand Down

0 comments on commit 66b2512

Please sign in to comment.