Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Continue - Option to enable specific language or ecosystem cataloger #888

Closed
wants to merge 1 commit into from
Closed
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
cataloger select one,group
Signed-off-by: houdini91 <mdstrauss91@gmail.com>
houdini91 committed Apr 17, 2022
commit 46c24eb3dcfffbf381517dcbd4d3a8e624a689c3
23 changes: 23 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -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:
25 changes: 19 additions & 6 deletions cmd/packages.go
Original file line number Diff line number Diff line change
@@ -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",
)
}

@@ -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 {
4 changes: 4 additions & 0 deletions internal/config/pkg.go
Original file line number Diff line number Diff line change
@@ -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) {
@@ -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
@@ -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
}
69 changes: 65 additions & 4 deletions syft/pkg/cataloger/cataloger.go
Original file line number Diff line number Diff line change
@@ -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"
@@ -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.
@@ -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(),
@@ -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(),
@@ -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
@@ -5,7 +5,9 @@ import (
)

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

func DefaultConfig() Config {
2 changes: 1 addition & 1 deletion test/integration/catalog_packages_test.go
Original file line number Diff line number Diff line change
@@ -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)