Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,29 @@ package:
# same as -s ; SYFT_PACKAGE_CATALOGER_SCOPE env var
scope: "squashed"

# Cataloger group select
# When Empty default select for each scheme - Dir:Index, Image:installed
# Options: [index install all].
# cataloger-group: ""

# enable specific language or ecosystem cataloger
# default: select catalogers out of group
# catalogers:
# - "ruby-gemfile-cataloger"
# - "ruby-gemspec-cataloger"
# - "python-index-cataloger"
# - "python-package-cataloger"
# - "javascript-lock-cataloger"
# - "javascript-package-cataloger"
# - "php-composer-installed-cataloger"
# - "php-composer-lock-cataloger"
# - "dpkgdb-cataloger"
# - "rpmdb-cataloger"
# - "java-cataloger"
# - "apkdb-cataloger"
# - "go-module-binary-cataloger"
catalogers:

# cataloging file classifications is exposed through the power-user subcommand
file-classification:
cataloger:
Expand Down
25 changes: 19 additions & 6 deletions cmd/packages.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,18 +137,23 @@ func setPackageFlags(flags *pflag.FlagSet) {
)

flags.StringArrayP(
"exclude", "", nil,
"exclude paths from being scanned using a glob expression",
"exclude", "", nil, "exclude paths from being scanned using a glob expression",
)

flags.StringArrayP(
"cataloger", "C", nil, "enable specific language or ecosystem cataloger",
)

flags.StringP(
"cataloger-group", "", "", fmt.Sprintf("selection cataloger group, options=%v", cataloger.AllGroups),
)

flags.Bool(
"overwrite-existing-image", false,
"overwrite an existing image during the upload to Anchore Enterprise",
"overwrite-existing-image", false, "overwrite an existing image during the upload to Anchore Enterprise",
)

flags.Uint(
"import-timeout", 30,
"set a timeout duration (in seconds) for the upload to Anchore Enterprise",
"import-timeout", 30, "set a timeout duration (in seconds) for the upload to Anchore Enterprise",
)
}

Expand Down Expand Up @@ -180,6 +185,14 @@ func bindExclusivePackagesConfigOptions(flags *pflag.FlagSet) error {
return err
}

if err := viper.BindPFlag("package.catalogers", flags.Lookup("cataloger")); err != nil {
return err
}

if err := viper.BindPFlag("package.cataloger-group", flags.Lookup("cataloger-group")); err != nil {
return err
}

// Upload options //////////////////////////////////////////////////////////

if err := viper.BindPFlag("anchore.host", flags.Lookup("host")); err != nil {
Expand Down
4 changes: 4 additions & 0 deletions internal/config/pkg.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ type pkg struct {
Cataloger catalogerOptions `yaml:"cataloger" json:"cataloger" mapstructure:"cataloger"`
SearchUnindexedArchives bool `yaml:"search-unindexed-archives" json:"search-unindexed-archives" mapstructure:"search-unindexed-archives"`
SearchIndexedArchives bool `yaml:"search-indexed-archives" json:"search-indexed-archives" mapstructure:"search-indexed-archives"`
Catalogers []string `yaml:"catalogers" json:"catalogers" mapstructure:"catalogers"`
CatalogerGroup cataloger.Group `yaml:"cataloger-group" json:"cataloger-group" mapstructure:"cataloger-group"`
}

func (cfg pkg) loadDefaultValues(v *viper.Viper) {
Expand All @@ -29,5 +31,7 @@ func (cfg pkg) ToConfig() cataloger.Config {
IncludeUnindexedArchives: cfg.SearchUnindexedArchives,
Scope: cfg.Cataloger.ScopeOpt,
},
Catalogers: cfg.Catalogers,
CatalogerGroup: cfg.CatalogerGroup,
}
}
34 changes: 19 additions & 15 deletions syft/lib.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,23 +48,27 @@ func CatalogPackages(src *source.Source, cfg cataloger.Config) (*pkg.Catalog, []
log.Info("could not identify distro")
}

// conditionally use the correct set of loggers based on the input type (container image or directory)
var catalogers []cataloger.Cataloger
switch src.Metadata.Scheme {
case source.ImageScheme:
log.Info("cataloging image")
catalogers = cataloger.ImageCatalogers(cfg)
case source.FileScheme:
log.Info("cataloging file")
catalogers = cataloger.AllCatalogers(cfg)
case source.DirectoryScheme:
log.Info("cataloging directory")
catalogers = cataloger.DirectoryCatalogers(cfg)
default:
return nil, nil, nil, fmt.Errorf("unable to determine cataloger set from scheme=%+v", src.Metadata.Scheme)
// conditionally use the correct set of catalogers based on the scheme (container image or directory)
if cfg.CatalogerGroup == "" {
switch src.Metadata.Scheme {
case source.ImageScheme:
cfg.CatalogerGroup = cataloger.InstallationGroup
case source.FileScheme:
cfg.CatalogerGroup = cataloger.AllGroup
case source.DirectoryScheme:
cfg.CatalogerGroup = cataloger.IndexGroup
default:
return nil, nil, nil, fmt.Errorf("unable to determine cataloger set from scheme=%+v", src.Metadata.Scheme)
}
}

catalog, relationships, err := cataloger.Catalog(resolver, release, catalogers...)
groupCatalogers, err := cataloger.SelectGroup(cfg)
if err != nil {
return nil, nil, nil, err
}
enabledCatalogers := cataloger.FilterCatalogers(cfg, groupCatalogers)

catalog, relationships, err := cataloger.Catalog(resolver, release, enabledCatalogers...)
if err != nil {
return nil, nil, nil, err
}
Expand Down
69 changes: 65 additions & 4 deletions syft/pkg/cataloger/cataloger.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ catalogers defined in child packages as well as the interface definition to impl
package cataloger

import (
"fmt"

"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/apkdb"
Expand All @@ -22,6 +25,20 @@ import (
"github.com/anchore/syft/syft/source"
)

type Group string

const (
IndexGroup Group = "index"
InstallationGroup Group = "install"
AllGroup Group = "all"
)

var AllGroups = []Group{
IndexGroup,
InstallationGroup,
AllGroup,
}

// Cataloger describes behavior for an object to participate in parsing container image or file system
// contents for the purpose of discovering Packages. Each concrete implementation should focus on discovering Packages
// for a specific Package Type or ecosystem.
Expand All @@ -32,8 +49,8 @@ type Cataloger interface {
Catalog(resolver source.FileResolver) ([]pkg.Package, []artifact.Relationship, error)
}

// ImageCatalogers returns a slice of locally implemented catalogers that are fit for detecting installations of packages.
func ImageCatalogers(cfg Config) []Cataloger {
// InstallationCatalogers returns a slice of locally implemented catalogers that are fit for detecting installations of packages.
func InstallationCatalogers(cfg Config) []Cataloger {
return []Cataloger{
ruby.NewGemSpecCataloger(),
python.NewPythonPackageCataloger(),
Expand All @@ -47,8 +64,8 @@ func ImageCatalogers(cfg Config) []Cataloger {
}
}

// 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 {
// IndexCatalogers returns a slice of locally implemented catalogers that are fit for detecting packages from index files (and select installations)
func IndexCatalogers(cfg Config) []Cataloger {
return []Cataloger{
ruby.NewGemFileLockCataloger(),
python.NewPythonIndexCataloger(),
Expand Down Expand Up @@ -85,3 +102,47 @@ func AllCatalogers(cfg Config) []Cataloger {
dart.NewPubspecLockCataloger(),
}
}

func SelectGroup(cfg Config) ([]Cataloger, error) {
switch cfg.CatalogerGroup {
case IndexGroup:
log.Info("cataloging index group")
return IndexCatalogers(cfg), nil
case InstallationGroup:
log.Info("cataloging installation group")
return InstallationCatalogers(cfg), nil
case AllGroup:
log.Info("cataloging all group")
return AllCatalogers(cfg), nil
default:
return nil, fmt.Errorf("unknown cataloger group, Group: %s", cfg.CatalogerGroup)
}
}

func FilterCatalogers(cfg Config, groupCatalogers []Cataloger) []Cataloger {
return filterCatalogers(groupCatalogers, cfg.Catalogers)
}

func filterCatalogers(catalogers []Cataloger, enabledCatalogers []string) []Cataloger {
// if enable-cataloger is not set, all applicable catalogers are enabled by default
if len(enabledCatalogers) == 0 {
return catalogers
}
var filteredCatalogers []Cataloger
for _, cataloger := range catalogers {
if contains(enabledCatalogers, cataloger.Name()) {
filteredCatalogers = append(filteredCatalogers, cataloger)
}
}
return filteredCatalogers
}

func contains(catalogers []string, str string) bool {
for _, cataloger := range catalogers {
if cataloger == str ||
fmt.Sprintf("%s-cataloger", cataloger) == str {
return true
}
}
return false
}
4 changes: 3 additions & 1 deletion syft/pkg/cataloger/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ import (
)

type Config struct {
Search SearchConfig
Search SearchConfig
Catalogers []string
CatalogerGroup Group
}

func DefaultConfig() Config {
Expand Down
2 changes: 1 addition & 1 deletion test/integration/catalog_packages_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ func BenchmarkImagePackageCatalogers(b *testing.B) {
tarPath := imagetest.GetFixtureImageTarPath(b, fixtureImageName)

var pc *pkg.Catalog
for _, c := range cataloger.ImageCatalogers(cataloger.DefaultConfig()) {
for _, c := range cataloger.InstallationCatalogers(cataloger.DefaultConfig()) {
// in case of future alteration where state is persisted, assume no dependency is safe to reuse
userInput := "docker-archive:" + tarPath
sourceInput, err := source.ParseInput(userInput, "", false)
Expand Down