mirror of
https://github.com/anchore/syft.git
synced 2025-11-17 16:33:21 +01:00
fix: add manual vendor/product removal to fix false flags (#1070)
Closes https://github.com/anchore/syft/issues/1066 Closes https://github.com/anchore/grype/issues/800 Closes https://github.com/anchore/grype/issues/491
This commit is contained in:
parent
f1a124209a
commit
668f102340
@ -11,6 +11,12 @@ type candidateComposite struct {
|
||||
candidateAddition
|
||||
}
|
||||
|
||||
type candidateRemovalComposite struct {
|
||||
pkg.Type
|
||||
candidateKey
|
||||
candidateRemovals
|
||||
}
|
||||
|
||||
// defaultCandidateAdditions is all of the known cases for product and vendor field values that should be used when
|
||||
// select package information is discovered
|
||||
var defaultCandidateAdditions = buildCandidateLookup(
|
||||
@ -123,6 +129,16 @@ var defaultCandidateAdditions = buildCandidateLookup(
|
||||
},
|
||||
})
|
||||
|
||||
var defaultCandidateRemovals = buildCandidateRemovalLookup(
|
||||
[]candidateRemovalComposite{
|
||||
// Python packages
|
||||
{
|
||||
pkg.PythonPkg,
|
||||
candidateKey{PkgName: "redis"},
|
||||
candidateRemovals{VendorsToRemove: []string{"redis"}},
|
||||
},
|
||||
})
|
||||
|
||||
// buildCandidateLookup is a convenience function for creating the defaultCandidateAdditions set
|
||||
func buildCandidateLookup(cc []candidateComposite) (ca map[pkg.Type]map[candidateKey]candidateAddition) {
|
||||
ca = make(map[pkg.Type]map[candidateKey]candidateAddition)
|
||||
@ -136,12 +152,30 @@ func buildCandidateLookup(cc []candidateComposite) (ca map[pkg.Type]map[candidat
|
||||
return ca
|
||||
}
|
||||
|
||||
// buildCandidateRemovalLookup is a convenience function for creating the defaultCandidateRemovals set
|
||||
func buildCandidateRemovalLookup(cc []candidateRemovalComposite) (ca map[pkg.Type]map[candidateKey]candidateRemovals) {
|
||||
ca = make(map[pkg.Type]map[candidateKey]candidateRemovals)
|
||||
for _, c := range cc {
|
||||
if _, ok := ca[c.Type]; !ok {
|
||||
ca[c.Type] = make(map[candidateKey]candidateRemovals)
|
||||
}
|
||||
ca[c.Type][c.candidateKey] = c.candidateRemovals
|
||||
}
|
||||
return ca
|
||||
}
|
||||
|
||||
// candidateKey represents the set of inputs that should be matched on in order to signal more candidate additions to be used.
|
||||
type candidateKey struct {
|
||||
Vendor string
|
||||
PkgName string
|
||||
}
|
||||
|
||||
// candidateRemovals are the specific removals that should be considered during CPE generation (given a specific candidateKey)
|
||||
type candidateRemovals struct {
|
||||
ProductsToRemove []string
|
||||
VendorsToRemove []string
|
||||
}
|
||||
|
||||
// candidateAddition are the specific additions that should be considered during CPE generation (given a specific candidateKey)
|
||||
type candidateAddition struct {
|
||||
AdditionalProducts []string
|
||||
@ -192,3 +226,35 @@ func findAdditionalProducts(allAdditions map[pkg.Type]map[candidateKey]candidate
|
||||
|
||||
return products
|
||||
}
|
||||
|
||||
// findVendorsToRemove searches all possible vendor removals that could be removed during the CPE generation process (given package info + a vendor candidate)
|
||||
func findVendorsToRemove(allRemovals map[pkg.Type]map[candidateKey]candidateRemovals, ty pkg.Type, pkgName string) (vendors []string) {
|
||||
removals, ok := allRemovals[ty]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
if removal, ok := removals[candidateKey{
|
||||
PkgName: pkgName,
|
||||
}]; ok {
|
||||
vendors = append(vendors, removal.VendorsToRemove...)
|
||||
}
|
||||
|
||||
return vendors
|
||||
}
|
||||
|
||||
// findProductsToRemove searches all possible product removals that could be removed during the CPE generation process (given package info)
|
||||
func findProductsToRemove(allRemovals map[pkg.Type]map[candidateKey]candidateRemovals, ty pkg.Type, pkgName string) (products []string) {
|
||||
removals, ok := allRemovals[ty]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
if removal, ok := removals[candidateKey{
|
||||
PkgName: pkgName,
|
||||
}]; ok {
|
||||
products = append(products, removal.ProductsToRemove...)
|
||||
}
|
||||
|
||||
return products
|
||||
}
|
||||
|
||||
@ -154,3 +154,81 @@ func Test_additionalVendors(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_findVendorsToRemove(t *testing.T) {
|
||||
//GIVEN
|
||||
tests := []struct {
|
||||
name string
|
||||
ty pkg.Type
|
||||
pkgName string
|
||||
expected []string
|
||||
}{
|
||||
{
|
||||
name: "vendor removal match by input package name",
|
||||
ty: pkg.JavaPkg,
|
||||
pkgName: "my-package-name",
|
||||
expected: []string{"awesome-vendor-addition"},
|
||||
},
|
||||
{
|
||||
name: "vendor removal miss by input package name",
|
||||
ty: pkg.JavaPkg,
|
||||
pkgName: "my-package-name-1",
|
||||
},
|
||||
}
|
||||
|
||||
allRemovals := map[pkg.Type]map[candidateKey]candidateRemovals{
|
||||
pkg.JavaPkg: {
|
||||
candidateKey{
|
||||
PkgName: "my-package-name",
|
||||
}: {
|
||||
VendorsToRemove: []string{"awesome-vendor-addition"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
//WHEN + THEN
|
||||
assert.Equal(t, test.expected, findVendorsToRemove(allRemovals, test.ty, test.pkgName))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_findProductsToRemove(t *testing.T) {
|
||||
//GIVEN
|
||||
tests := []struct {
|
||||
name string
|
||||
ty pkg.Type
|
||||
pkgName string
|
||||
expected []string
|
||||
}{
|
||||
{
|
||||
name: "vendor removal match by input package name",
|
||||
ty: pkg.JavaPkg,
|
||||
pkgName: "my-package-name",
|
||||
expected: []string{"awesome-vendor-addition"},
|
||||
},
|
||||
{
|
||||
name: "vendor removal miss by input package name",
|
||||
ty: pkg.JavaPkg,
|
||||
pkgName: "my-package-name-1",
|
||||
},
|
||||
}
|
||||
|
||||
allRemovals := map[pkg.Type]map[candidateKey]candidateRemovals{
|
||||
pkg.JavaPkg: {
|
||||
candidateKey{
|
||||
PkgName: "my-package-name",
|
||||
}: {
|
||||
ProductsToRemove: []string{"awesome-vendor-addition"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
//WHEN + THEN
|
||||
assert.Equal(t, test.expected, findProductsToRemove(allRemovals, test.ty, test.pkgName))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -116,6 +116,9 @@ func candidateVendors(p pkg.Package) []string {
|
||||
vendors.addValue(findAdditionalVendors(defaultCandidateAdditions, p.Type, p.Name, vendor)...)
|
||||
}
|
||||
|
||||
// remove known mis
|
||||
vendors.removeByValue(findVendorsToRemove(defaultCandidateRemovals, p.Type, p.Name)...)
|
||||
|
||||
return vendors.uniqueValues()
|
||||
}
|
||||
|
||||
@ -148,6 +151,9 @@ func candidateProducts(p pkg.Package) []string {
|
||||
// add known candidate additions
|
||||
products.addValue(findAdditionalProducts(defaultCandidateAdditions, p.Type, p.Name)...)
|
||||
|
||||
// remove known candidate removals
|
||||
products.removeByValue(findProductsToRemove(defaultCandidateRemovals, p.Type, p.Name)...)
|
||||
|
||||
return products.uniqueValues()
|
||||
}
|
||||
|
||||
|
||||
@ -666,6 +666,27 @@ func TestGeneratePackageCPEs(t *testing.T) {
|
||||
"cpe:2.3:a:stephanie_morillo:bundler:2.1.4:*:*:*:*:*:*:*",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "regression: python redis shadows normal redis",
|
||||
p: pkg.Package{
|
||||
Name: "redis",
|
||||
Version: "2.1.4",
|
||||
Type: pkg.PythonPkg,
|
||||
FoundBy: "some-analyzer",
|
||||
Language: pkg.Python,
|
||||
},
|
||||
expected: []string{
|
||||
"cpe:2.3:a:python-redis:python-redis:2.1.4:*:*:*:*:*:*:*",
|
||||
"cpe:2.3:a:python-redis:python_redis:2.1.4:*:*:*:*:*:*:*",
|
||||
"cpe:2.3:a:python-redis:redis:2.1.4:*:*:*:*:*:*:*",
|
||||
"cpe:2.3:a:python:python-redis:2.1.4:*:*:*:*:*:*:*",
|
||||
"cpe:2.3:a:python:python_redis:2.1.4:*:*:*:*:*:*:*",
|
||||
"cpe:2.3:a:python:redis:2.1.4:*:*:*:*:*:*:*",
|
||||
"cpe:2.3:a:python_redis:python-redis:2.1.4:*:*:*:*:*:*:*",
|
||||
"cpe:2.3:a:python_redis:python_redis:2.1.4:*:*:*:*:*:*:*",
|
||||
"cpe:2.3:a:python_redis:redis:2.1.4:*:*:*:*:*:*:*",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user