Add catalogers configuration (#1038)

* Option to enable specific language or ecosystem cataloger

Signed-off-by: ramanan-ravi <ramanan@deepfence.io>
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* Disable dotnet cataloger

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* Option to enable specific language or ecosystem cataloger

Signed-off-by: Ramanan Ravikumar <ramanan@deepfence.io>
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* rename "enable-cataloger" option to "catalogers"

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* add cli test for --catalogers option

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* update readme with latest cataloger names

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* enable dotnet cataloger

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* fix linting

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* fix cataloger imports

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* update readme with alpmdb cataloger config example

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

Co-authored-by: ramanan-ravi <ramanan@deepfence.io>
This commit is contained in:
Alex Goodman
2022-06-21 13:06:25 +00:00
committed by GitHub
co-authored by ramanan-ravi
parent aed1599c4d
commit ea611dab5f
9 changed files with 322 additions and 32 deletions
+38 -5
View File
@@ -6,6 +6,9 @@ catalogers defined in child packages as well as the interface definition to impl
package cataloger
import (
"strings"
"github.com/anchore/syft/internal/log"
"github.com/anchore/syft/syft/artifact"
"github.com/anchore/syft/syft/pkg"
"github.com/anchore/syft/syft/pkg/cataloger/alpm"
@@ -36,7 +39,7 @@ type Cataloger interface {
// ImageCatalogers returns a slice of locally implemented catalogers that are fit for detecting installations of packages.
func ImageCatalogers(cfg Config) []Cataloger {
return []Cataloger{
return filterCatalogers([]Cataloger{
alpm.NewAlpmdbCataloger(),
ruby.NewGemSpecCataloger(),
python.NewPythonPackageCataloger(),
@@ -48,12 +51,12 @@ func ImageCatalogers(cfg Config) []Cataloger {
apkdb.NewApkdbCataloger(),
golang.NewGoModuleBinaryCataloger(),
dotnet.NewDotnetDepsCataloger(),
}
}, cfg.Catalogers)
}
// DirectoryCatalogers returns a slice of locally implemented catalogers that are fit for detecting packages from index files (and select installations)
func DirectoryCatalogers(cfg Config) []Cataloger {
return []Cataloger{
return filterCatalogers([]Cataloger{
alpm.NewAlpmdbCataloger(),
ruby.NewGemFileLockCataloger(),
python.NewPythonIndexCataloger(),
@@ -69,12 +72,12 @@ func DirectoryCatalogers(cfg Config) []Cataloger {
rust.NewCargoLockCataloger(),
dart.NewPubspecLockCataloger(),
dotnet.NewDotnetDepsCataloger(),
}
}, cfg.Catalogers)
}
// AllCatalogers returns all implemented catalogers
func AllCatalogers(cfg Config) []Cataloger {
return []Cataloger{
return filterCatalogers([]Cataloger{
alpm.NewAlpmdbCataloger(),
ruby.NewGemFileLockCataloger(),
ruby.NewGemSpecCataloger(),
@@ -91,5 +94,35 @@ func AllCatalogers(cfg Config) []Cataloger {
rust.NewCargoLockCataloger(),
dart.NewPubspecLockCataloger(),
dotnet.NewDotnetDepsCataloger(),
}, cfg.Catalogers)
}
func filterCatalogers(catalogers []Cataloger, enabledCatalogerPatterns []string) []Cataloger {
// if cataloger is not set, all applicable catalogers are enabled by default
if len(enabledCatalogerPatterns) == 0 {
return catalogers
}
var keepCatalogers []Cataloger
for _, cataloger := range catalogers {
if contains(enabledCatalogerPatterns, cataloger.Name()) {
keepCatalogers = append(keepCatalogers, cataloger)
continue
}
log.Infof("skipping cataloger %q", cataloger.Name())
}
return keepCatalogers
}
func contains(enabledPartial []string, catalogerName string) bool {
catalogerName = strings.TrimSuffix(catalogerName, "-cataloger")
for _, partial := range enabledPartial {
partial = strings.TrimSuffix(partial, "-cataloger")
if partial == "" {
continue
}
if strings.Contains(catalogerName, partial) {
return true
}
}
return false
}
+201
View File
@@ -0,0 +1,201 @@
package cataloger
import (
"github.com/anchore/syft/syft/artifact"
"github.com/anchore/syft/syft/pkg"
"github.com/anchore/syft/syft/source"
"github.com/stretchr/testify/assert"
"testing"
)
var _ Cataloger = (*dummy)(nil)
type dummy struct {
name string
}
func (d dummy) Name() string {
return d.name
}
func (d dummy) Catalog(_ source.FileResolver) ([]pkg.Package, []artifact.Relationship, error) {
panic("not implemented")
}
func Test_filterCatalogers(t *testing.T) {
tests := []struct {
name string
patterns []string
catalogers []string
want []string
}{
{
name: "no filtering",
patterns: nil,
catalogers: []string{
"ruby-gemspec-cataloger",
"python-package-cataloger",
"php-composer-installed-cataloger",
"javascript-package-cataloger",
"dpkgdb-cataloger",
"rpmdb-cataloger",
"java-cataloger",
"apkdb-cataloger",
"go-module-binary-cataloger",
},
want: []string{
"ruby-gemspec-cataloger",
"python-package-cataloger",
"php-composer-installed-cataloger",
"javascript-package-cataloger",
"dpkgdb-cataloger",
"rpmdb-cataloger",
"java-cataloger",
"apkdb-cataloger",
"go-module-binary-cataloger",
},
},
{
name: "exact name match",
patterns: []string{
"rpmdb-cataloger",
"javascript-package-cataloger",
},
catalogers: []string{
"ruby-gemspec-cataloger",
"python-package-cataloger",
"php-composer-installed-cataloger",
"javascript-package-cataloger",
"dpkgdb-cataloger",
"rpmdb-cataloger",
"java-cataloger",
"apkdb-cataloger",
"go-module-binary-cataloger",
},
want: []string{
"javascript-package-cataloger",
"rpmdb-cataloger",
},
},
{
name: "partial name match",
patterns: []string{
"ruby",
"installed",
},
catalogers: []string{
"ruby-gemspec-cataloger",
"ruby-gemfile-cataloger",
"python-package-cataloger",
"php-composer-installed-cataloger",
"javascript-package-cataloger",
"dpkgdb-cataloger",
"rpmdb-cataloger",
"java-cataloger",
"apkdb-cataloger",
"go-module-binary-cataloger",
},
want: []string{
"php-composer-installed-cataloger",
"ruby-gemspec-cataloger",
"ruby-gemfile-cataloger",
},
},
{
name: "ignore 'cataloger' keyword",
patterns: []string{
"cataloger",
},
catalogers: []string{
"ruby-gemspec-cataloger",
"ruby-gemfile-cataloger",
"python-package-cataloger",
"php-composer-installed-cataloger",
"javascript-package-cataloger",
"dpkgdb-cataloger",
"rpmdb-cataloger",
"java-cataloger",
"apkdb-cataloger",
"go-module-binary-cataloger",
},
want: []string{},
},
{
name: "only some patterns match",
patterns: []string{
"cataloger",
"go-module",
},
catalogers: []string{
"ruby-gemspec-cataloger",
"ruby-gemfile-cataloger",
"python-package-cataloger",
"php-composer-installed-cataloger",
"javascript-package-cataloger",
"dpkgdb-cataloger",
"rpmdb-cataloger",
"java-cataloger",
"apkdb-cataloger",
"go-module-binary-cataloger",
},
want: []string{
"go-module-binary-cataloger",
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
var catalogers []Cataloger
for _, n := range tt.catalogers {
catalogers = append(catalogers, dummy{name: n})
}
got := filterCatalogers(catalogers, tt.patterns)
var gotNames []string
for _, g := range got {
gotNames = append(gotNames, g.Name())
}
assert.ElementsMatch(t, tt.want, gotNames)
})
}
}
func Test_contains(t *testing.T) {
type args struct {
}
tests := []struct {
name string
enabledCatalogers []string
catalogerName string
want bool
}{
{
name: "keep exact match",
enabledCatalogers: []string{
"php-composer-installed-cataloger",
},
catalogerName: "php-composer-installed-cataloger",
want: true,
},
{
name: "match substring",
enabledCatalogers: []string{
"python",
},
catalogerName: "python-package-cataloger",
want: true,
},
{
name: "dont match on 'cataloger'",
enabledCatalogers: []string{
"cataloger",
},
catalogerName: "python-package-cataloger",
want: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assert.Equal(t, tt.want, contains(tt.enabledCatalogers, tt.catalogerName))
})
}
}
+2 -1
View File
@@ -5,7 +5,8 @@ import (
)
type Config struct {
Search SearchConfig
Search SearchConfig
Catalogers []string
}
func DefaultConfig() Config {