Add filters to package cataloger (#1021)

* Add filters to package cataloger

This PR adds filters so a package without name or version doesn't go in
the list of all discovered packages.

Integration and cli tests were added to validate the feature.

Signed-off-by: Jonas Xavier <jonasx@anchore.com>

* add nolint:funlen to cataloger/catalog.go

Signed-off-by: Jonas Xavier <jonasx@anchore.com>

* don't require package version

Signed-off-by: Jonas Xavier <jonasx@anchore.com>

* add package filtering to generic and python cataloger

also removes cli tests in favor of integration and unit tests

Signed-off-by: Jonas Xavier <jonasx@anchore.com>

* drop nolint:funlen

Signed-off-by: Jonas Xavier <jonasx@anchore.com>

* check for no-removal operation

Signed-off-by: Jonas Xavier <jonasx@anchore.com>

* remove unused fixtures

Signed-off-by: Jonas Xavier <jonasx@anchore.com>

* rename no-version file to hide semantic version

Signed-off-by: Jonas Xavier <jonasx@anchore.com>

* drop integration tests and add pkg func for validation

Signed-off-by: Jonas Xavier <jonasx@anchore.com>

* python cataloger use global pkg validation

Signed-off-by: Jonas Xavier <jonasx@anchore.com>

* check for valid packages on deb/go/rpm catalogers

Signed-off-by: Jonas Xavier <jonasx@anchore.com>

* update rpm cataloger after rebase

Signed-off-by: Jonas Xavier <jonasx@anchore.com>

* nit with pointers

Signed-off-by: Jonas Xavier <jonasx@anchore.com>

* simpler use of package validation

Signed-off-by: Jonas Xavier <jonasx@anchore.com>

* remmove double pkg validations

Signed-off-by: Jonas Xavier <jonasx@anchore.com>

* rename func param to artifactsToExclude

Signed-off-by: Jonas Xavier <jonasx@anchore.com>

* add test for relationships and bug fix

Signed-off-by: Jonas Xavier <jonasx@anchore.com>

* feedback changes

Signed-off-by: Jonas Xavier <jonasx@anchore.com>
This commit is contained in:
Jonas Xavier
2022-06-03 13:17:43 -04:00
committed by GitHub
parent 82de24cf7c
commit caff67289a
17 changed files with 269 additions and 26 deletions
@@ -7,28 +7,31 @@ import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/anchore/syft/syft/artifact"
"github.com/anchore/syft/syft/pkg"
"github.com/anchore/syft/syft/source"
)
func parser(_ string, reader io.Reader) ([]*pkg.Package, []artifact.Relationship, error) {
contents, err := ioutil.ReadAll(reader)
if err != nil {
panic(err)
}
return []*pkg.Package{
{
Name: string(contents),
},
}, nil, nil
}
func TestGenericCataloger(t *testing.T) {
allParsedPathes := make(map[string]bool)
parser := func(path string, reader io.Reader) ([]*pkg.Package, []artifact.Relationship, error) {
allParsedPathes[path] = true
contents, err := ioutil.ReadAll(reader)
require.NoError(t, err)
p := &pkg.Package{Name: string(contents)}
r := artifact.Relationship{From: p, To: p,
Type: artifact.ContainsRelationship,
}
return []*pkg.Package{p}, []artifact.Relationship{r}, nil
}
globParsers := map[string]ParserFn{
"**/a-path.txt": parser,
"**/empty.txt": parser,
}
pathParsers := map[string]ParserFn{
"test-fixtures/another-path.txt": parser,
@@ -36,21 +39,27 @@ func TestGenericCataloger(t *testing.T) {
}
upstream := "some-other-cataloger"
expectedSelection := []string{"test-fixtures/last/path.txt", "test-fixtures/another-path.txt", "test-fixtures/a-path.txt"}
expectedSelection := []string{"test-fixtures/last/path.txt", "test-fixtures/another-path.txt", "test-fixtures/a-path.txt", "test-fixtures/empty.txt"}
resolver := source.NewMockResolverForPaths(expectedSelection...)
cataloger := NewGenericCataloger(pathParsers, globParsers, upstream)
actualPkgs, relationships, err := cataloger.Catalog(resolver)
assert.NoError(t, err)
expectedPkgs := make(map[string]pkg.Package)
for _, path := range expectedSelection {
require.True(t, allParsedPathes[path])
expectedPkgs[path] = pkg.Package{
FoundBy: upstream,
Name: fmt.Sprintf("%s file contents!", path),
}
}
actualPkgs, _, err := cataloger.Catalog(resolver)
assert.NoError(t, err)
assert.Len(t, actualPkgs, len(expectedPkgs))
assert.Len(t, allParsedPathes, len(expectedSelection))
// empty.txt won't become a package
assert.Len(t, actualPkgs, len(expectedPkgs)-1)
// right now, a relationship is created for each package, but if the relationship includes an invalid package it should be dropped.
assert.Len(t, relationships, len(actualPkgs))
for _, p := range actualPkgs {
ref := p.Locations.ToSlice()[0]
@@ -69,3 +78,99 @@ func TestGenericCataloger(t *testing.T) {
}
}
}
func Test_removeRelationshipsWithArtifactIDs(t *testing.T) {
one := &pkg.Package{Name: "one", Version: "1.0"}
two := &pkg.Package{Name: "two", Version: "1.0"}
three := &pkg.Package{Name: "three", Version: "1.0"}
four := &pkg.Package{Name: "four", Version: "bla"}
five := &pkg.Package{Name: "five", Version: "1.0"}
pkgs := make([]artifact.Identifiable, 0)
for _, p := range []*pkg.Package{one, two, three, four, five} {
// IDs are necessary for comparison
p.SetID()
pkgs = append(pkgs, p)
}
type args struct {
remove map[artifact.ID]struct{}
relationships []artifact.Relationship
}
tests := []struct {
name string
args args
want []artifact.Relationship
}{
{
name: "nothing-to-remove",
args: args{
relationships: []artifact.Relationship{
{From: one, To: two},
},
},
want: []artifact.Relationship{
{From: one, To: two},
},
},
{
name: "remove-all-relationships",
args: args{
remove: map[artifact.ID]struct{}{
one.ID(): {},
three.ID(): {},
},
relationships: []artifact.Relationship{
{From: one, To: two},
{From: two, To: three},
{From: three, To: four},
},
},
want: []artifact.Relationship(nil),
},
{
name: "remove-half-of-relationships",
args: args{
remove: map[artifact.ID]struct{}{
one.ID(): {},
},
relationships: []artifact.Relationship{
{From: one, To: two},
{From: one, To: three},
{From: two, To: three},
{From: three, To: four},
},
},
want: []artifact.Relationship{
{From: two, To: three},
{From: three, To: four},
},
},
{
name: "remove-repeated-relationships",
args: args{
remove: map[artifact.ID]struct{}{
one.ID(): {},
two.ID(): {},
},
relationships: []artifact.Relationship{
{From: one, To: two},
{From: one, To: three},
{From: two, To: three},
{From: two, To: three},
{From: three, To: four},
{From: four, To: five},
},
},
want: []artifact.Relationship{
{From: three, To: four},
{From: four, To: five},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assert.Equalf(t, tt.want, removeRelationshipsWithArtifactIDs(tt.args.remove, tt.args.relationships), "removeRelationshipsWithArtifactIDs(%v, %v)", tt.args.remove, tt.args.relationships)
})
}
}