mirror of
https://github.com/anchore/syft.git
synced 2026-11-05 00:46:38 +01:00
chore: refactor basic CPE functionality to its own package (#1436)
This commit is contained in:
@@ -5,13 +5,14 @@ import (
|
||||
|
||||
"github.com/facebookincubator/nvdtools/wfn"
|
||||
|
||||
"github.com/anchore/syft/syft/cpe"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
)
|
||||
|
||||
const jenkinsName = "jenkins"
|
||||
|
||||
// filterFn instances should return true if the given CPE should be removed from a collection for the given package
|
||||
type filterFn func(cpe pkg.CPE, p pkg.Package) bool
|
||||
type filterFn func(cpe cpe.CPE, p pkg.Package) bool
|
||||
|
||||
var cpeFilters = []filterFn{
|
||||
disallowJiraClientServerMismatch,
|
||||
@@ -20,23 +21,23 @@ var cpeFilters = []filterFn{
|
||||
disallowNonParseableCPEs,
|
||||
}
|
||||
|
||||
func filter(cpes []pkg.CPE, p pkg.Package, filters ...filterFn) (result []pkg.CPE) {
|
||||
func filter(cpes []cpe.CPE, p pkg.Package, filters ...filterFn) (result []cpe.CPE) {
|
||||
cpeLoop:
|
||||
for _, cpe := range cpes {
|
||||
for _, c := range cpes {
|
||||
for _, fn := range filters {
|
||||
if fn(cpe, p) {
|
||||
if fn(c, p) {
|
||||
continue cpeLoop
|
||||
}
|
||||
}
|
||||
// all filter functions passed on filtering this CPE
|
||||
result = append(result, cpe)
|
||||
result = append(result, c)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func disallowNonParseableCPEs(cpe pkg.CPE, _ pkg.Package) bool {
|
||||
v := pkg.CPEString(cpe)
|
||||
_, err := pkg.NewCPE(v)
|
||||
func disallowNonParseableCPEs(c cpe.CPE, _ pkg.Package) bool {
|
||||
v := cpe.String(c)
|
||||
_, err := cpe.New(v)
|
||||
|
||||
cannotParse := err != nil
|
||||
|
||||
@@ -44,7 +45,7 @@ func disallowNonParseableCPEs(cpe pkg.CPE, _ pkg.Package) bool {
|
||||
}
|
||||
|
||||
// jenkins plugins should not match against jenkins
|
||||
func disallowJenkinsServerCPEForPluginPackage(cpe pkg.CPE, p pkg.Package) bool {
|
||||
func disallowJenkinsServerCPEForPluginPackage(cpe cpe.CPE, p pkg.Package) bool {
|
||||
if p.Type == pkg.JenkinsPluginPkg && cpe.Product == jenkinsName {
|
||||
return true
|
||||
}
|
||||
@@ -52,7 +53,7 @@ func disallowJenkinsServerCPEForPluginPackage(cpe pkg.CPE, p pkg.Package) bool {
|
||||
}
|
||||
|
||||
// filter to account that packages that are not for jenkins but have a CPE generated that will match against jenkins
|
||||
func disallowJenkinsCPEsNotAssociatedWithJenkins(cpe pkg.CPE, p pkg.Package) bool {
|
||||
func disallowJenkinsCPEsNotAssociatedWithJenkins(cpe cpe.CPE, p pkg.Package) bool {
|
||||
// jenkins server should only match against a product with the name jenkins
|
||||
if cpe.Product == jenkinsName && !strings.Contains(strings.ToLower(p.Name), jenkinsName) {
|
||||
if cpe.Vendor == wfn.Any || cpe.Vendor == jenkinsName || cpe.Vendor == "cloudbees" {
|
||||
@@ -63,7 +64,7 @@ func disallowJenkinsCPEsNotAssociatedWithJenkins(cpe pkg.CPE, p pkg.Package) boo
|
||||
}
|
||||
|
||||
// filter to account for packages which are jira client packages but have a CPE that will match against jira
|
||||
func disallowJiraClientServerMismatch(cpe pkg.CPE, p pkg.Package) bool {
|
||||
func disallowJiraClientServerMismatch(cpe cpe.CPE, p pkg.Package) bool {
|
||||
// jira / atlassian should not apply to clients
|
||||
if cpe.Product == "jira" && strings.Contains(strings.ToLower(p.Name), "client") {
|
||||
if cpe.Vendor == wfn.Any || cpe.Vendor == "jira" || cpe.Vendor == "atlassian" {
|
||||
|
||||
@@ -5,19 +5,20 @@ import (
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/anchore/syft/syft/cpe"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
)
|
||||
|
||||
func Test_disallowJenkinsServerCPEForPluginPackage(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
cpe pkg.CPE
|
||||
cpe cpe.CPE
|
||||
pkg pkg.Package
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
name: "go case (filter out)",
|
||||
cpe: pkg.MustCPE("cpe:2.3:a:name:jenkins:3.2:*:*:*:*:*:*:*"),
|
||||
cpe: cpe.Must("cpe:2.3:a:name:jenkins:3.2:*:*:*:*:*:*:*"),
|
||||
pkg: pkg.Package{
|
||||
Type: pkg.JenkinsPluginPkg,
|
||||
},
|
||||
@@ -25,7 +26,7 @@ func Test_disallowJenkinsServerCPEForPluginPackage(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "ignore jenkins plugins with unique name",
|
||||
cpe: pkg.MustCPE("cpe:2.3:a:name:ci-jenkins:3.2:*:*:*:*:*:*:*"),
|
||||
cpe: cpe.Must("cpe:2.3:a:name:ci-jenkins:3.2:*:*:*:*:*:*:*"),
|
||||
pkg: pkg.Package{
|
||||
Type: pkg.JenkinsPluginPkg,
|
||||
},
|
||||
@@ -33,7 +34,7 @@ func Test_disallowJenkinsServerCPEForPluginPackage(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "ignore java packages",
|
||||
cpe: pkg.MustCPE("cpe:2.3:a:name:jenkins:3.2:*:*:*:*:*:*:*"),
|
||||
cpe: cpe.Must("cpe:2.3:a:name:jenkins:3.2:*:*:*:*:*:*:*"),
|
||||
pkg: pkg.Package{
|
||||
Type: pkg.JavaPkg,
|
||||
},
|
||||
@@ -50,13 +51,13 @@ func Test_disallowJenkinsServerCPEForPluginPackage(t *testing.T) {
|
||||
func Test_disallowJenkinsCPEsNotAssociatedWithJenkins(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
cpe pkg.CPE
|
||||
cpe cpe.CPE
|
||||
pkg pkg.Package
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
name: "filter out mismatched name (cloudbees vendor)",
|
||||
cpe: pkg.MustCPE("cpe:2.3:a:cloudbees:jenkins:3.2:*:*:*:*:*:*:*"),
|
||||
cpe: cpe.Must("cpe:2.3:a:cloudbees:jenkins:3.2:*:*:*:*:*:*:*"),
|
||||
pkg: pkg.Package{
|
||||
Name: "not-j*nkins",
|
||||
Type: pkg.JavaPkg,
|
||||
@@ -65,7 +66,7 @@ func Test_disallowJenkinsCPEsNotAssociatedWithJenkins(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "filter out mismatched name (jenkins vendor)",
|
||||
cpe: pkg.MustCPE("cpe:2.3:a:jenkins:jenkins:3.2:*:*:*:*:*:*:*"),
|
||||
cpe: cpe.Must("cpe:2.3:a:jenkins:jenkins:3.2:*:*:*:*:*:*:*"),
|
||||
pkg: pkg.Package{
|
||||
Name: "not-j*nkins",
|
||||
Type: pkg.JavaPkg,
|
||||
@@ -74,7 +75,7 @@ func Test_disallowJenkinsCPEsNotAssociatedWithJenkins(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "filter out mismatched name (any vendor)",
|
||||
cpe: pkg.MustCPE("cpe:2.3:a:*:jenkins:3.2:*:*:*:*:*:*:*"),
|
||||
cpe: cpe.Must("cpe:2.3:a:*:jenkins:3.2:*:*:*:*:*:*:*"),
|
||||
pkg: pkg.Package{
|
||||
Name: "not-j*nkins",
|
||||
Type: pkg.JavaPkg,
|
||||
@@ -83,7 +84,7 @@ func Test_disallowJenkinsCPEsNotAssociatedWithJenkins(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "ignore packages with the name jenkins",
|
||||
cpe: pkg.MustCPE("cpe:2.3:a:*:jenkins:3.2:*:*:*:*:*:*:*"),
|
||||
cpe: cpe.Must("cpe:2.3:a:*:jenkins:3.2:*:*:*:*:*:*:*"),
|
||||
pkg: pkg.Package{
|
||||
Name: "jenkins-thing",
|
||||
Type: pkg.JavaPkg,
|
||||
@@ -92,7 +93,7 @@ func Test_disallowJenkinsCPEsNotAssociatedWithJenkins(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "ignore product names that are not exactly 'jenkins'",
|
||||
cpe: pkg.MustCPE("cpe:2.3:a:*:jenkins-something-else:3.2:*:*:*:*:*:*:*"),
|
||||
cpe: cpe.Must("cpe:2.3:a:*:jenkins-something-else:3.2:*:*:*:*:*:*:*"),
|
||||
pkg: pkg.Package{
|
||||
Name: "not-j*nkins",
|
||||
Type: pkg.JavaPkg,
|
||||
@@ -110,13 +111,13 @@ func Test_disallowJenkinsCPEsNotAssociatedWithJenkins(t *testing.T) {
|
||||
func Test_disallowJiraClientServerMismatch(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
cpe pkg.CPE
|
||||
cpe cpe.CPE
|
||||
pkg pkg.Package
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
name: "filter out mismatched name (atlassian vendor)",
|
||||
cpe: pkg.MustCPE("cpe:2.3:a:atlassian:jira:3.2:*:*:*:*:*:*:*"),
|
||||
cpe: cpe.Must("cpe:2.3:a:atlassian:jira:3.2:*:*:*:*:*:*:*"),
|
||||
pkg: pkg.Package{
|
||||
Name: "something-client",
|
||||
Type: pkg.JavaPkg,
|
||||
@@ -125,7 +126,7 @@ func Test_disallowJiraClientServerMismatch(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "filter out mismatched name (jira vendor)",
|
||||
cpe: pkg.MustCPE("cpe:2.3:a:jira:jira:3.2:*:*:*:*:*:*:*"),
|
||||
cpe: cpe.Must("cpe:2.3:a:jira:jira:3.2:*:*:*:*:*:*:*"),
|
||||
pkg: pkg.Package{
|
||||
Name: "something-client",
|
||||
Type: pkg.JavaPkg,
|
||||
@@ -134,7 +135,7 @@ func Test_disallowJiraClientServerMismatch(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "filter out mismatched name (any vendor)",
|
||||
cpe: pkg.MustCPE("cpe:2.3:a:*:jira:3.2:*:*:*:*:*:*:*"),
|
||||
cpe: cpe.Must("cpe:2.3:a:*:jira:3.2:*:*:*:*:*:*:*"),
|
||||
pkg: pkg.Package{
|
||||
Name: "something-client",
|
||||
Type: pkg.JavaPkg,
|
||||
@@ -143,7 +144,7 @@ func Test_disallowJiraClientServerMismatch(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "ignore package names that do not have 'client'",
|
||||
cpe: pkg.MustCPE("cpe:2.3:a:*:jira:3.2:*:*:*:*:*:*:*"),
|
||||
cpe: cpe.Must("cpe:2.3:a:*:jira:3.2:*:*:*:*:*:*:*"),
|
||||
pkg: pkg.Package{
|
||||
Name: "jira-thing",
|
||||
Type: pkg.JavaPkg,
|
||||
@@ -152,7 +153,7 @@ func Test_disallowJiraClientServerMismatch(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "ignore product names that are not exactly 'jira'",
|
||||
cpe: pkg.MustCPE("cpe:2.3:a:*:jira-something-else:3.2:*:*:*:*:*:*:*"),
|
||||
cpe: cpe.Must("cpe:2.3:a:*:jira-something-else:3.2:*:*:*:*:*:*:*"),
|
||||
pkg: pkg.Package{
|
||||
Name: "not-j*ra",
|
||||
Type: pkg.JavaPkg,
|
||||
|
||||
@@ -10,26 +10,27 @@ import (
|
||||
"github.com/facebookincubator/nvdtools/wfn"
|
||||
|
||||
"github.com/anchore/syft/internal"
|
||||
"github.com/anchore/syft/syft/cpe"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
)
|
||||
|
||||
func newCPE(product, vendor, version, targetSW string) *wfn.Attributes {
|
||||
cpe := *(wfn.NewAttributesWithAny())
|
||||
cpe.Part = "a"
|
||||
cpe.Product = product
|
||||
cpe.Vendor = vendor
|
||||
cpe.Version = version
|
||||
cpe.TargetSW = targetSW
|
||||
if pkg.ValidateCPEString(pkg.CPEString(cpe)) != nil {
|
||||
c := *(wfn.NewAttributesWithAny())
|
||||
c.Part = "a"
|
||||
c.Product = product
|
||||
c.Vendor = vendor
|
||||
c.Version = version
|
||||
c.TargetSW = targetSW
|
||||
if cpe.ValidateString(cpe.String(c)) != nil {
|
||||
return nil
|
||||
}
|
||||
return &cpe
|
||||
return &c
|
||||
}
|
||||
|
||||
// Generate Create a list of CPEs for a given package, trying to guess the vendor, product tuple. We should be trying to
|
||||
// generate the minimal set of representative CPEs, which implies that optional fields should not be included
|
||||
// (such as target SW).
|
||||
func Generate(p pkg.Package) []pkg.CPE {
|
||||
func Generate(p pkg.Package) []cpe.CPE {
|
||||
vendors := candidateVendors(p)
|
||||
products := candidateProducts(p)
|
||||
if len(products) == 0 {
|
||||
@@ -37,7 +38,7 @@ func Generate(p pkg.Package) []pkg.CPE {
|
||||
}
|
||||
|
||||
keys := internal.NewStringSet()
|
||||
cpes := make([]pkg.CPE, 0)
|
||||
cpes := make([]cpe.CPE, 0)
|
||||
for _, product := range products {
|
||||
for _, vendor := range vendors {
|
||||
// prevent duplicate entries...
|
||||
@@ -47,8 +48,8 @@ func Generate(p pkg.Package) []pkg.CPE {
|
||||
}
|
||||
keys.Add(key)
|
||||
// add a new entry...
|
||||
if cpe := newCPE(product, vendor, p.Version, wfn.Any); cpe != nil {
|
||||
cpes = append(cpes, *cpe)
|
||||
if c := newCPE(product, vendor, p.Version, wfn.Any); c != nil {
|
||||
cpes = append(cpes, *c)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -56,7 +57,7 @@ func Generate(p pkg.Package) []pkg.CPE {
|
||||
// filter out any known combinations that don't accurately represent this package
|
||||
cpes = filter(cpes, p, cpeFilters...)
|
||||
|
||||
sort.Sort(pkg.CPEBySpecificity(cpes))
|
||||
sort.Sort(cpe.BySpecificity(cpes))
|
||||
|
||||
return cpes
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"github.com/scylladb/go-set/strset"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/anchore/syft/syft/cpe"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
)
|
||||
|
||||
@@ -696,7 +697,7 @@ func TestGeneratePackageCPEs(t *testing.T) {
|
||||
expectedCpeSet := set.NewStringSet(test.expected...)
|
||||
actualCpeSet := set.NewStringSet()
|
||||
for _, a := range actual {
|
||||
actualCpeSet.Add(pkg.CPEString(a))
|
||||
actualCpeSet.Add(cpe.String(a))
|
||||
}
|
||||
|
||||
extra := strset.Difference(actualCpeSet, expectedCpeSet).List()
|
||||
|
||||
Reference in New Issue
Block a user