From 0c29090b42d985c19f45fef0d1d394306310b158 Mon Sep 17 00:00:00 2001 From: Alex Goodman Date: Wed, 21 Apr 2021 08:59:48 -0400 Subject: [PATCH] Add hyphen replacement logic for CPE generation (#397) * add hyphen replacement logic for CPE generation Signed-off-by: Alex Goodman * migrate "python-" vendor prefix to product candidate processing Signed-off-by: Alex Goodman * bump linter timeout for CI Signed-off-by: Alex Goodman * update cpe candidate product tests Signed-off-by: Alex Goodman --- Makefile | 2 +- syft/pkg/cataloger/cpe.go | 18 +++++--- syft/pkg/cataloger/cpe_test.go | 76 ++++++++++++++++++++++++++++++++-- 3 files changed, 87 insertions(+), 9 deletions(-) diff --git a/Makefile b/Makefile index 60815c8ad..1b6a9103e 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ TEMPDIR = ./.tmp RESULTSDIR = test/results COVER_REPORT = $(RESULTSDIR)/unit-coverage-details.txt COVER_TOTAL = $(RESULTSDIR)/unit-coverage-summary.txt -LINTCMD = $(TEMPDIR)/golangci-lint run --tests=false --config .golangci.yaml +LINTCMD = $(TEMPDIR)/golangci-lint run --tests=false --timeout=2m --config .golangci.yaml ACC_TEST_IMAGE = centos:8.2.2004 ACC_DIR = ./test/acceptance BOLD := $(shell tput -T linux bold) diff --git a/syft/pkg/cataloger/cpe.go b/syft/pkg/cataloger/cpe.go index 0a8ad7c3a..f51e08582 100644 --- a/syft/pkg/cataloger/cpe.go +++ b/syft/pkg/cataloger/cpe.go @@ -125,10 +125,7 @@ func candidateVendors(p pkg.Package) []string { // TODO: Confirm whether using products as vendors is helpful to the matching process vendors := candidateProducts(p) - switch p.Language { - case pkg.Python: - vendors = append(vendors, fmt.Sprintf("python-%s", p.Name)) - case pkg.Java: + if p.Language == pkg.Java { if p.MetadataType == pkg.JavaMetadataType { vendors = append(vendors, candidateVendorsForJava(p)...) } @@ -139,10 +136,21 @@ func candidateVendors(p pkg.Package) []string { func candidateProducts(p pkg.Package) []string { products := []string{p.Name} - if p.Language == pkg.Java { + switch p.Language { + case pkg.Python: + if !strings.HasPrefix(p.Name, "python") { + products = append(products, "python-"+p.Name) + } + case pkg.Java: products = append(products, candidateProductsForJava(p)...) } + for _, prod := range products { + if strings.Contains(prod, "-") { + products = append(products, strings.ReplaceAll(prod, "-", "_")) + } + } + // return any known product name swaps prepended to the results return append(productCandidatesByPkgType.getCandidates(p.Type, p.Name), products...) } diff --git a/syft/pkg/cataloger/cpe_test.go b/syft/pkg/cataloger/cpe_test.go index 17289344f..91a6fec67 100644 --- a/syft/pkg/cataloger/cpe_test.go +++ b/syft/pkg/cataloger/cpe_test.go @@ -17,6 +17,58 @@ func TestGeneratePackageCPEs(t *testing.T) { p pkg.Package expected []string }{ + { + name: "hyphen replacement", + p: pkg.Package{ + Name: "name-part", + Version: "3.2", + FoundBy: "some-analyzer", + Language: pkg.Python, + Type: pkg.DebPkg, + }, + expected: []string{ + "cpe:2.3:a:*:name-part:3.2:*:*:*:*:*:*:*", + "cpe:2.3:a:*:name-part:3.2:*:*:*:*:python:*:*", + "cpe:2.3:a:name-part:name-part:3.2:*:*:*:*:*:*:*", + "cpe:2.3:a:name-part:name-part:3.2:*:*:*:*:python:*:*", + "cpe:2.3:a:python-name-part:name-part:3.2:*:*:*:*:*:*:*", + "cpe:2.3:a:python-name-part:name-part:3.2:*:*:*:*:python:*:*", + "cpe:2.3:a:*:name_part:3.2:*:*:*:*:*:*:*", + "cpe:2.3:a:*:name_part:3.2:*:*:*:*:python:*:*", + "cpe:2.3:a:name_part:name_part:3.2:*:*:*:*:*:*:*", + "cpe:2.3:a:name_part:name_part:3.2:*:*:*:*:python:*:*", + "cpe:2.3:a:python_name_part:name_part:3.2:*:*:*:*:*:*:*", + "cpe:2.3:a:python_name_part:name_part:3.2:*:*:*:*:python:*:*", + "cpe:2.3:a:name-part:name_part:3.2:*:*:*:*:*:*:*", + "cpe:2.3:a:name-part:name_part:3.2:*:*:*:*:python:*:*", + "cpe:2.3:a:name_part:name-part:3.2:*:*:*:*:*:*:*", + "cpe:2.3:a:name_part:name-part:3.2:*:*:*:*:python:*:*", + "cpe:2.3:a:python-name-part:name_part:3.2:*:*:*:*:*:*:*", + "cpe:2.3:a:python-name-part:name_part:3.2:*:*:*:*:python:*:*", + "cpe:2.3:a:python_name_part:name-part:3.2:*:*:*:*:*:*:*", + "cpe:2.3:a:python_name_part:name-part:3.2:*:*:*:*:python:*:*", + "cpe:2.3:a:*:python-name-part:3.2:*:*:*:*:*:*:*", + "cpe:2.3:a:*:python-name-part:3.2:*:*:*:*:python:*:*", + "cpe:2.3:a:*:python_name_part:3.2:*:*:*:*:*:*:*", + "cpe:2.3:a:*:python_name_part:3.2:*:*:*:*:python:*:*", + "cpe:2.3:a:name-part:python-name-part:3.2:*:*:*:*:*:*:*", + "cpe:2.3:a:name-part:python-name-part:3.2:*:*:*:*:python:*:*", + "cpe:2.3:a:name-part:python_name_part:3.2:*:*:*:*:*:*:*", + "cpe:2.3:a:name-part:python_name_part:3.2:*:*:*:*:python:*:*", + "cpe:2.3:a:name_part:python-name-part:3.2:*:*:*:*:*:*:*", + "cpe:2.3:a:name_part:python-name-part:3.2:*:*:*:*:python:*:*", + "cpe:2.3:a:name_part:python_name_part:3.2:*:*:*:*:*:*:*", + "cpe:2.3:a:name_part:python_name_part:3.2:*:*:*:*:python:*:*", + "cpe:2.3:a:python-name-part:python-name-part:3.2:*:*:*:*:*:*:*", + "cpe:2.3:a:python-name-part:python-name-part:3.2:*:*:*:*:python:*:*", + "cpe:2.3:a:python-name-part:python_name_part:3.2:*:*:*:*:*:*:*", + "cpe:2.3:a:python-name-part:python_name_part:3.2:*:*:*:*:python:*:*", + "cpe:2.3:a:python_name_part:python-name-part:3.2:*:*:*:*:*:*:*", + "cpe:2.3:a:python_name_part:python-name-part:3.2:*:*:*:*:python:*:*", + "cpe:2.3:a:python_name_part:python_name_part:3.2:*:*:*:*:*:*:*", + "cpe:2.3:a:python_name_part:python_name_part:3.2:*:*:*:*:python:*:*", + }, + }, { name: "python language", p: pkg.Package{ @@ -33,6 +85,24 @@ func TestGeneratePackageCPEs(t *testing.T) { "cpe:2.3:a:name:name:3.2:*:*:*:*:python:*:*", "cpe:2.3:a:python-name:name:3.2:*:*:*:*:*:*:*", "cpe:2.3:a:python-name:name:3.2:*:*:*:*:python:*:*", + "cpe:2.3:a:python_name:name:3.2:*:*:*:*:*:*:*", + "cpe:2.3:a:python_name:name:3.2:*:*:*:*:python:*:*", + "cpe:2.3:a:*:python-name:3.2:*:*:*:*:*:*:*", + "cpe:2.3:a:*:python-name:3.2:*:*:*:*:python:*:*", + "cpe:2.3:a:*:python_name:3.2:*:*:*:*:*:*:*", + "cpe:2.3:a:*:python_name:3.2:*:*:*:*:python:*:*", + "cpe:2.3:a:name:python-name:3.2:*:*:*:*:*:*:*", + "cpe:2.3:a:name:python-name:3.2:*:*:*:*:python:*:*", + "cpe:2.3:a:name:python_name:3.2:*:*:*:*:*:*:*", + "cpe:2.3:a:name:python_name:3.2:*:*:*:*:python:*:*", + "cpe:2.3:a:python-name:python-name:3.2:*:*:*:*:*:*:*", + "cpe:2.3:a:python-name:python-name:3.2:*:*:*:*:python:*:*", + "cpe:2.3:a:python-name:python_name:3.2:*:*:*:*:*:*:*", + "cpe:2.3:a:python-name:python_name:3.2:*:*:*:*:python:*:*", + "cpe:2.3:a:python_name:python-name:3.2:*:*:*:*:*:*:*", + "cpe:2.3:a:python_name:python-name:3.2:*:*:*:*:python:*:*", + "cpe:2.3:a:python_name:python_name:3.2:*:*:*:*:*:*:*", + "cpe:2.3:a:python_name:python_name:3.2:*:*:*:*:python:*:*", }, }, { @@ -222,7 +292,7 @@ func TestCandidateProducts(t *testing.T) { }, }, }, - expected: []string{"itunes", "some-java-package-with-group-id"}, + expected: []string{"itunes", "some-java-package-with-group-id", "some_java_package_with_group_id"}, }, { p: pkg.Package{ @@ -235,7 +305,7 @@ func TestCandidateProducts(t *testing.T) { }, }, }, - expected: []string{"some-jenkins-plugin"}, + expected: []string{"some-jenkins-plugin", "some_jenkins_plugin"}, }, { p: pkg.Package{ @@ -256,7 +326,7 @@ func TestCandidateProducts(t *testing.T) { Name: "python-rrdtool", Type: pkg.PythonPkg, }, - expected: []string{"rrdtool" /* <-- known good names | default guess --> */, "python-rrdtool"}, + expected: []string{"rrdtool" /* <-- known good names | default guess --> */, "python-rrdtool", "python_rrdtool"}, }, }