From a864dc950544cf8e01762e3dc1487cda5dc020f9 Mon Sep 17 00:00:00 2001 From: Arnout Engelen Date: Thu, 12 Jan 2023 20:16:53 +0100 Subject: [PATCH] feat: prefer known CPE vendors over other candidates (#1294) * feat: prefer known CPE vendors over other candidates All ASF projects will be under the `apache` vendor in CPE, and indeed this is already one of the candidates, but the logic for selecting the 'most specific' CPE string would select for example `apache_software_foundation` or `commons-text`. This is not necessarily 'wrong' in the CPE candidate selection logic: there is no way to reliably determine the right candidate. I think it makes sense to use specific data around the vendor candidate generation, somewhat similar to 'defaultCandidateAdditions'. Unfortunately there are still a few CVE's for old (pre-5.x, long unsupported) tomcat versions that are actually tagged with `apache_software_foundation`, but I'm not sure those are worth spending time on. Signed-off-by: Arnout Engelen * chore: swap out array of vendors for set data structure Signed-off-by: Alex Goodman Signed-off-by: Arnout Engelen Signed-off-by: Alex Goodman Co-authored-by: Alex Goodman --- syft/pkg/cataloger/common/cpe/generate.go | 16 +++++++++- .../pkg/cataloger/common/cpe/generate_test.go | 29 +------------------ 2 files changed, 16 insertions(+), 29 deletions(-) diff --git a/syft/pkg/cataloger/common/cpe/generate.go b/syft/pkg/cataloger/common/cpe/generate.go index a67f7a9eb..ec686cccf 100644 --- a/syft/pkg/cataloger/common/cpe/generate.go +++ b/syft/pkg/cataloger/common/cpe/generate.go @@ -8,12 +8,17 @@ import ( "strings" "github.com/facebookincubator/nvdtools/wfn" + "github.com/scylladb/go-set/strset" "github.com/anchore/syft/internal" "github.com/anchore/syft/syft/cpe" "github.com/anchore/syft/syft/pkg" ) +// knownVendors contains vendor strings that are known to exist in +// the CPE database, so they will be preferred over other candidates: +var knownVendors = strset.New("apache") + func newCPE(product, vendor, version, targetSW string) *wfn.Attributes { c := *(wfn.NewAttributesWithAny()) c.Part = "a" @@ -120,7 +125,16 @@ func candidateVendors(p pkg.Package) []string { // remove known mis vendors.removeByValue(findVendorsToRemove(defaultCandidateRemovals, p.Type, p.Name)...) - return vendors.uniqueValues() + uniqueVendors := vendors.uniqueValues() + + // if any known vendor was detected, pick that one. + for _, vendor := range uniqueVendors { + if knownVendors.Has(vendor) { + return []string{vendor} + } + } + + return uniqueVendors } func candidateProducts(p pkg.Package) []string { diff --git a/syft/pkg/cataloger/common/cpe/generate_test.go b/syft/pkg/cataloger/common/cpe/generate_test.go index e078444f3..2b1f581c0 100644 --- a/syft/pkg/cataloger/common/cpe/generate_test.go +++ b/syft/pkg/cataloger/common/cpe/generate_test.go @@ -279,36 +279,9 @@ func TestGeneratePackageCPEs(t *testing.T) { }, }, expected: []string{ - "cpe:2.3:a:apache-software-foundation:cxf-rt-bindings-xml:3.3.10:*:*:*:*:*:*:*", - "cpe:2.3:a:apache-software-foundation:cxf:3.3.10:*:*:*:*:*:*:*", - "cpe:2.3:a:apache-software-foundation:cxf_rt_bindings_xml:3.3.10:*:*:*:*:*:*:*", "cpe:2.3:a:apache:cxf-rt-bindings-xml:3.3.10:*:*:*:*:*:*:*", "cpe:2.3:a:apache:cxf:3.3.10:*:*:*:*:*:*:*", "cpe:2.3:a:apache:cxf_rt_bindings_xml:3.3.10:*:*:*:*:*:*:*", - "cpe:2.3:a:apache_software_foundation:cxf-rt-bindings-xml:3.3.10:*:*:*:*:*:*:*", - "cpe:2.3:a:apache_software_foundation:cxf:3.3.10:*:*:*:*:*:*:*", - "cpe:2.3:a:apache_software_foundation:cxf_rt_bindings_xml:3.3.10:*:*:*:*:*:*:*", - "cpe:2.3:a:cxf-rt-bindings-xml:cxf-rt-bindings-xml:3.3.10:*:*:*:*:*:*:*", - "cpe:2.3:a:cxf-rt-bindings-xml:cxf:3.3.10:*:*:*:*:*:*:*", - "cpe:2.3:a:cxf-rt-bindings-xml:cxf_rt_bindings_xml:3.3.10:*:*:*:*:*:*:*", - "cpe:2.3:a:cxf-rt-bindings:cxf-rt-bindings-xml:3.3.10:*:*:*:*:*:*:*", - "cpe:2.3:a:cxf-rt-bindings:cxf:3.3.10:*:*:*:*:*:*:*", - "cpe:2.3:a:cxf-rt-bindings:cxf_rt_bindings_xml:3.3.10:*:*:*:*:*:*:*", - "cpe:2.3:a:cxf-rt:cxf-rt-bindings-xml:3.3.10:*:*:*:*:*:*:*", - "cpe:2.3:a:cxf-rt:cxf:3.3.10:*:*:*:*:*:*:*", - "cpe:2.3:a:cxf-rt:cxf_rt_bindings_xml:3.3.10:*:*:*:*:*:*:*", - "cpe:2.3:a:cxf:cxf-rt-bindings-xml:3.3.10:*:*:*:*:*:*:*", - "cpe:2.3:a:cxf:cxf:3.3.10:*:*:*:*:*:*:*", - "cpe:2.3:a:cxf:cxf_rt_bindings_xml:3.3.10:*:*:*:*:*:*:*", - "cpe:2.3:a:cxf_rt:cxf-rt-bindings-xml:3.3.10:*:*:*:*:*:*:*", - "cpe:2.3:a:cxf_rt:cxf:3.3.10:*:*:*:*:*:*:*", - "cpe:2.3:a:cxf_rt:cxf_rt_bindings_xml:3.3.10:*:*:*:*:*:*:*", - "cpe:2.3:a:cxf_rt_bindings:cxf-rt-bindings-xml:3.3.10:*:*:*:*:*:*:*", - "cpe:2.3:a:cxf_rt_bindings:cxf:3.3.10:*:*:*:*:*:*:*", - "cpe:2.3:a:cxf_rt_bindings:cxf_rt_bindings_xml:3.3.10:*:*:*:*:*:*:*", - "cpe:2.3:a:cxf_rt_bindings_xml:cxf-rt-bindings-xml:3.3.10:*:*:*:*:*:*:*", - "cpe:2.3:a:cxf_rt_bindings_xml:cxf:3.3.10:*:*:*:*:*:*:*", - "cpe:2.3:a:cxf_rt_bindings_xml:cxf_rt_bindings_xml:3.3.10:*:*:*:*:*:*:*", }, }, { @@ -838,7 +811,7 @@ func TestCandidateVendor(t *testing.T) { Name: "log4j", Type: pkg.JavaPkg, }, - expected: []string{"apache" /* <-- known good names | default guess --> */, "log4j"}, + expected: []string{"apache"}, }, }