diff --git a/syft/pkg/cataloger/common/cpe/field_candidate.go b/syft/pkg/cataloger/common/cpe/field_candidate.go index 8fa7743f989..5c4f64a97cc 100644 --- a/syft/pkg/cataloger/common/cpe/field_candidate.go +++ b/syft/pkg/cataloger/common/cpe/field_candidate.go @@ -46,6 +46,16 @@ func (s fieldCandidateSet) add(candidates ...fieldCandidate) { } } +func (s fieldCandidateSet) removeByValue(values ...string) { + for _, value := range values { + for candidate := range s { + if candidate.value == value { + delete(s, candidate) + } + } + } +} + func (s fieldCandidateSet) clear() { for k := range s { delete(s, k) diff --git a/syft/pkg/cataloger/common/cpe/field_candidate_test.go b/syft/pkg/cataloger/common/cpe/field_candidate_test.go index 9f55c9a118b..3ad001a491b 100644 --- a/syft/pkg/cataloger/common/cpe/field_candidate_test.go +++ b/syft/pkg/cataloger/common/cpe/field_candidate_test.go @@ -261,3 +261,33 @@ func Test_cpeFieldCandidateSet_uniqueValues(t *testing.T) { assert.ElementsMatch(t, []string{"1", "2", "3"}, set.uniqueValues()) } + +func Test_cpeFieldCandidateSet_removeByValue(t *testing.T) { + s := newFieldCandidateSet() + // should be removed + s.add(fieldCandidate{ + value: "1", + disallowSubSelections: true, + disallowDelimiterVariations: true, + }) + s.add(fieldCandidate{ + value: "1", + disallowSubSelections: true, + }) + s.add(fieldCandidate{ + value: "1", + disallowDelimiterVariations: true, + }) + s.add(fieldCandidate{ + value: "1", + }) + // should not be removed + s.add(fieldCandidate{ + value: "2", + }) + assert.Len(t, s.values(), 5) + + s.removeByValue("1") + + assert.Len(t, s.values(), 1) +} diff --git a/syft/pkg/cataloger/common/cpe/generate.go b/syft/pkg/cataloger/common/cpe/generate.go index fbbd55665d7..7b82fd519c2 100644 --- a/syft/pkg/cataloger/common/cpe/generate.go +++ b/syft/pkg/cataloger/common/cpe/generate.go @@ -151,6 +151,9 @@ func candidateProducts(p pkg.Package) []string { products.addValue(prod) } } + // it is never OK to have candidates with these values ["" and "*"] (since CPEs will match any other value) + products.removeByValue("") + products.removeByValue("*") // try swapping hyphens for underscores, vice versa, and removing separators altogether addDelimiterVariations(products) diff --git a/syft/pkg/cataloger/common/cpe/generate_test.go b/syft/pkg/cataloger/common/cpe/generate_test.go index 3105b5ea0aa..f357e3e99cc 100644 --- a/syft/pkg/cataloger/common/cpe/generate_test.go +++ b/syft/pkg/cataloger/common/cpe/generate_test.go @@ -511,10 +511,12 @@ func TestGeneratePackageCPEs(t *testing.T) { func TestCandidateProducts(t *testing.T) { tests := []struct { + name string p pkg.Package expected []string }{ { + name: "springframework", p: pkg.Package{ Name: "springframework", Type: pkg.JavaPkg, @@ -522,6 +524,7 @@ func TestCandidateProducts(t *testing.T) { expected: []string{"spring_framework", "springsource_spring_framework" /* <-- known good names | default guess --> */, "springframework"}, }, { + name: "java", p: pkg.Package{ Name: "some-java-package-with-group-id", Type: pkg.JavaPkg, @@ -535,6 +538,21 @@ func TestCandidateProducts(t *testing.T) { expected: []string{"itunes", "some-java-package-with-group-id", "some_java_package_with_group_id"}, }, { + name: "java-with-asterisk", + p: pkg.Package{ + Name: "some-java-package-with-group-id", + Type: pkg.JavaPkg, + Language: pkg.Java, + Metadata: pkg.JavaMetadata{ + PomProperties: &pkg.PomProperties{ + GroupID: "com.apple.itunes.*", + }, + }, + }, + expected: []string{"itunes", "some-java-package-with-group-id", "some_java_package_with_group_id"}, + }, + { + name: "jenkins-plugin", p: pkg.Package{ Name: "some-jenkins-plugin", Type: pkg.JenkinsPluginPkg, @@ -548,6 +566,7 @@ func TestCandidateProducts(t *testing.T) { expected: []string{"some-jenkins-plugin", "some_jenkins_plugin", "jenkins"}, }, { + name: "javascript", p: pkg.Package{ Name: "handlebars.js", Type: pkg.NpmPkg, @@ -555,6 +574,7 @@ func TestCandidateProducts(t *testing.T) { expected: []string{"handlebars" /* <-- known good names | default guess --> */, "handlebars.js"}, }, { + name: "gem", p: pkg.Package{ Name: "RedCloth", Type: pkg.GemPkg, @@ -562,6 +582,7 @@ func TestCandidateProducts(t *testing.T) { expected: []string{"redcloth_library" /* <-- known good names | default guess --> */, "RedCloth"}, }, { + name: "python", p: pkg.Package{ Name: "python-rrdtool", Type: pkg.PythonPkg,