add task id to constructor

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
This commit is contained in:
Alex Goodman 2022-06-07 17:44:24 -04:00
parent a5dd485672
commit b06a2d4f27
No known key found for this signature in database
GPG Key ID: 5CB45AE22BAB7EA7
23 changed files with 300 additions and 310 deletions

View File

@ -193,7 +193,7 @@ func attestationExecWorker(si source.Input, format sbom.Format, predicateType st
go func() { go func() {
defer close(errs) defer close(errs)
catalogingConfig, err := appConfig.ToCatalogingConfig() catalogingOpts, err := appConfig.ToCatalogingOptions()
if err != nil { if err != nil {
errs <- err errs <- err
return return
@ -208,7 +208,7 @@ func attestationExecWorker(si source.Input, format sbom.Format, predicateType st
return return
} }
s, err := generateSBOM(src, catalogingConfig) s, err := syft.Catalog(src, catalogingOpts...)
if err != nil { if err != nil {
errs <- err errs <- err
return return

View File

@ -112,6 +112,12 @@ func setPackageFlags(flags *pflag.FlagSet) {
"an optional platform specifier for container image sources (e.g. 'linux/arm64', 'linux/arm64/v8', 'arm64', 'linux')", "an optional platform specifier for container image sources (e.g. 'linux/arm64', 'linux/arm64/v8', 'arm64', 'linux')",
) )
flags.StringArrayP(
"cataloger", "", nil,
// TODO: have a nice way for a user to get the set of catalogers that exist
"set which catalogers to use when generating an SBOM",
)
// Upload options ////////////////////////////////////////////////////////// // Upload options //////////////////////////////////////////////////////////
flags.StringP( flags.StringP(
"host", "H", "", "host", "H", "",
@ -169,6 +175,10 @@ func bindExclusivePackagesConfigOptions(flags *pflag.FlagSet) error {
return err return err
} }
if err := viper.BindPFlag("catalogers", flags.Lookup("cataloger")); err != nil {
return err
}
if err := viper.BindPFlag("file", flags.Lookup("file")); err != nil { if err := viper.BindPFlag("file", flags.Lookup("file")); err != nil {
return err return err
} }
@ -257,18 +267,12 @@ func isVerbose() (result bool) {
return appConfig.CliOptions.Verbosity > 0 || isPipedInput return appConfig.CliOptions.Verbosity > 0 || isPipedInput
} }
func generateSBOM(src *source.Source, config *syft.CatalogingConfig) (*sbom.SBOM, error) {
return syft.Catalog(src,
syft.WithConfig(*config),
)
}
func packagesExecWorker(si source.Input, writer sbom.Writer) <-chan error { func packagesExecWorker(si source.Input, writer sbom.Writer) <-chan error {
errs := make(chan error) errs := make(chan error)
go func() { go func() {
defer close(errs) defer close(errs)
catalogingConfig, err := appConfig.ToCatalogingConfig() catalogingOpts, err := appConfig.ToCatalogingOptions()
if err != nil { if err != nil {
errs <- err errs <- err
return return
@ -283,7 +287,7 @@ func packagesExecWorker(si source.Input, writer sbom.Writer) <-chan error {
return return
} }
s, err := generateSBOM(src, catalogingConfig) s, err := syft.Catalog(src, catalogingOpts...)
if err != nil { if err != nil {
errs <- err errs <- err
return return

View File

@ -2,6 +2,7 @@ package cmd
import ( import (
"fmt" "fmt"
"github.com/anchore/syft/syft"
"os" "os"
"github.com/anchore/stereoscope" "github.com/anchore/stereoscope"
@ -110,7 +111,7 @@ func powerUserExecWorker(userInput string, writer sbom.Writer) <-chan error {
//appConfig.FileContents.Cataloger.Enabled = true //appConfig.FileContents.Cataloger.Enabled = true
//appConfig.FileClassification.Cataloger.Enabled = true //appConfig.FileClassification.Cataloger.Enabled = true
catalogingConfig, err := appConfig.ToCatalogingConfig() catalogingOpts, err := appConfig.ToCatalogingOptions()
if err != nil { if err != nil {
errs <- err errs <- err
return return
@ -131,7 +132,7 @@ func powerUserExecWorker(userInput string, writer sbom.Writer) <-chan error {
defer cleanup() defer cleanup()
} }
s, err := generateSBOM(src, catalogingConfig) s, err := syft.Catalog(src, catalogingOpts...)
if err != nil { if err != nil {
errs <- err errs <- err
return return

View File

@ -3,7 +3,6 @@ package config
import ( import (
"errors" "errors"
"fmt" "fmt"
"github.com/anchore/syft/syft/cataloger/files/fileclassifier"
"github.com/anchore/syft/syft/source" "github.com/anchore/syft/syft/source"
"path" "path"
"reflect" "reflect"
@ -42,6 +41,7 @@ type Application struct {
CheckForAppUpdate bool `yaml:"check-for-app-update" json:"check-for-app-update" mapstructure:"check-for-app-update"` // whether to check for an application update on start up or not CheckForAppUpdate bool `yaml:"check-for-app-update" json:"check-for-app-update" mapstructure:"check-for-app-update"` // whether to check for an application update on start up or not
Anchore anchore `yaml:"anchore" json:"anchore" mapstructure:"anchore"` // options for interacting with Anchore Engine/Enterprise Anchore anchore `yaml:"anchore" json:"anchore" mapstructure:"anchore"` // options for interacting with Anchore Engine/Enterprise
CliOptions CliOnlyOptions `yaml:"-" json:"-"` // all options only available through the CLI (not via env vars or config) CliOptions CliOnlyOptions `yaml:"-" json:"-"` // all options only available through the CLI (not via env vars or config)
Catalogers []string `yaml:"catalogers" json:"catalogers" mapstructure:"catalogers"`
Scope string `yaml:"scope" json:"scope" mapstructure:"scope"` Scope string `yaml:"scope" json:"scope" mapstructure:"scope"`
Dev development `yaml:"dev" json:"dev" mapstructure:"dev"` Dev development `yaml:"dev" json:"dev" mapstructure:"dev"`
Log logging `yaml:"log" json:"log" mapstructure:"log"` // all logging-related options Log logging `yaml:"log" json:"log" mapstructure:"log"` // all logging-related options
@ -55,7 +55,8 @@ type Application struct {
Platform string `yaml:"platform" json:"platform" mapstructure:"platform"` Platform string `yaml:"platform" json:"platform" mapstructure:"platform"`
} }
func (cfg Application) ToCatalogingConfig() (*syft.CatalogingConfig, error) { func (cfg Application) ToCatalogingOptions() ([]syft.CatalogingOption, error) {
digests, err := file.DigestHashesByName(cfg.FileMetadata.Digests...) digests, err := file.DigestHashesByName(cfg.FileMetadata.Digests...)
if err != nil { if err != nil {
return nil, fmt.Errorf("unable to parse config item 'file-metadata.digests': %w", err) return nil, fmt.Errorf("unable to parse config item 'file-metadata.digests': %w", err)
@ -76,19 +77,23 @@ func (cfg Application) ToCatalogingConfig() (*syft.CatalogingConfig, error) {
return nil, fmt.Errorf("bad scope value %q", cfg.Secrets.Scope) return nil, fmt.Errorf("bad scope value %q", cfg.Secrets.Scope)
} }
return &syft.CatalogingConfig{ c := syft.DefaultCatalogingConfig()
// note: package catalogers cannot be determined until runtime
ToolName: internal.ApplicationName, c.ToolVersion = version.FromBuild().Version
ToolVersion: version.FromBuild().Version, c.ToolConfiguration = &c
ToolConfiguration: cfg, c.DefaultScope = scopeOption
DefaultScope: scopeOption, c.ProcessTasksInSerial = false
ProcessTasksInSerial: false, c.DigestHashes = digests
DigestHashes: digests, c.SecretsSearch = *secretsConfig
SecretsSearch: *secretsConfig, c.SecretsScope = secretsScopeOption
SecretsScope: secretsScopeOption, c.ContentsSearch = cfg.FileContents.ToConfig()
FileClassifiers: fileclassifier.DefaultClassifiers(),
ContentsSearch: cfg.FileContents.ToConfig(), opts := []syft.CatalogingOption{
}, nil syft.WithConfig(c),
syft.WithCatalogers(cfg.Catalogers...),
}
return opts, nil
} }
// PowerUserCatalogerEnabledDefault switches all catalogers to be enabled when running power-user command // PowerUserCatalogerEnabledDefault switches all catalogers to be enabled when running power-user command
@ -142,6 +147,15 @@ func (cfg Application) loadDefaultValues(v *viper.Viper) {
} }
func (cfg *Application) parseConfigValues() error { func (cfg *Application) parseConfigValues() error {
// parse fields on application directyy
var catalogers []string
for _, c := range cfg.Catalogers {
for _, f := range strings.Split(c, ",") {
catalogers = append(catalogers, strings.TrimSpace(f))
}
}
cfg.Catalogers = catalogers
// parse application config options // parse application config options
for _, optionFn := range []func() error{ for _, optionFn := range []func() error{
cfg.parseUploadOptions, cfg.parseUploadOptions,

View File

@ -33,30 +33,24 @@ func Catalog(src *source.Source, options ...CatalogingOption) (*sbom.SBOM, error
} }
if config.availableTasks == nil { if config.availableTasks == nil {
config.availableTasks = newTaskCollection() var err error
config.availableTasks, err = newTaskCollection()
if err != nil {
return nil, err
} }
tc := config.availableTasks
if err := tc.addAllCatalogers(config); err != nil {
return nil, fmt.Errorf("unable to register catalogers: %w", err)
} }
var catalogingTasks []task
if len(config.EnabledCatalogers) == 0 { if len(config.EnabledCatalogers) == 0 {
switch src.Metadata.Scheme { return nil, fmt.Errorf("no cataloging tasks configured to run")
case source.ImageType:
catalogingTasks = tc.tasks(tc.withLabels(packageTaskLabel, installedTaskLabel)...)
case source.FileType:
catalogingTasks = tc.tasks(tc.all()...)
case source.DirectoryType:
// TODO: it looks like gemspec was left out on main, is this intentional? if so it's not accounted for here...
catalogingTasks = tc.tasks(tc.withLabels(packageTaskLabel)...)
} }
catalogingTasks, err := config.availableTasks.tasks(config, config.EnabledCatalogers...)
if err != nil {
return nil, err
} }
if len(catalogingTasks) == 0 { if len(catalogingTasks) == 0 {
return nil, fmt.Errorf("no cataloging tasks configured to run") return nil, fmt.Errorf("no cataloging tasks found to run")
} }
// special case: we need to identify the linux distro for downstream processing // special case: we need to identify the linux distro for downstream processing

View File

@ -14,5 +14,5 @@ func NewApkdbCataloger() *generic.Cataloger {
pkg.ApkDBGlob: parseApkDB, pkg.ApkDBGlob: parseApkDB,
} }
return generic.NewCataloger(nil, globParsers, "apkdb-cataloger") return generic.NewCataloger(nil, globParsers)
} }

View File

@ -32,11 +32,6 @@ func NewDpkgdbCataloger() *Cataloger {
return &Cataloger{} return &Cataloger{}
} }
// Name returns a string that uniquely describes a cataloger
func (c *Cataloger) Name() string {
return "dpkgdb-cataloger"
}
// Catalog is given an object to resolve file references and content, this function returns any discovered Packages after analyzing dpkg support files. // Catalog is given an object to resolve file references and content, this function returns any discovered Packages after analyzing dpkg support files.
func (c *Cataloger) Catalog(resolver file.Resolver) ([]pkg.Package, []artifact.Relationship, error) { func (c *Cataloger) Catalog(resolver file.Resolver) ([]pkg.Package, []artifact.Relationship, error) {
dbFileMatches, err := resolver.FilesByGlob(pkg.DpkgDBGlob) dbFileMatches, err := resolver.FilesByGlob(pkg.DpkgDBGlob)
@ -60,7 +55,6 @@ func (c *Cataloger) Catalog(resolver file.Resolver) ([]pkg.Package, []artifact.R
for i := range pkgs { for i := range pkgs {
p := &pkgs[i] p := &pkgs[i]
p.FoundBy = c.Name()
p.Locations = []file.Location{dbLocation} p.Locations = []file.Location{dbLocation}
// the current entry only has what may have been listed in the status file, however, there are additional // the current entry only has what may have been listed in the status file, however, there are additional

View File

@ -20,23 +20,16 @@ import (
type Cataloger struct { type Cataloger struct {
globParsers map[string]Parser globParsers map[string]Parser
pathParsers map[string]Parser pathParsers map[string]Parser
upstreamCataloger string
} }
// NewCataloger if provided path-to-parser-function and glob-to-parser-function lookups creates a Cataloger // NewCataloger if provided path-to-parser-function and glob-to-parser-function lookups creates a Cataloger
func NewCataloger(pathParsers map[string]Parser, globParsers map[string]Parser, upstreamCataloger string) *Cataloger { func NewCataloger(pathParsers map[string]Parser, globParsers map[string]Parser) *Cataloger {
return &Cataloger{ return &Cataloger{
globParsers: globParsers, globParsers: globParsers,
pathParsers: pathParsers, pathParsers: pathParsers,
upstreamCataloger: upstreamCataloger,
} }
} }
// Name returns a string that uniquely describes the upstream cataloger that this Generic Cataloger represents.
func (c *Cataloger) Name() string {
return c.upstreamCataloger
}
// Catalog is given an object to resolve file references and content, this function returns any discovered Packages after analyzing the catalog source. // Catalog is given an object to resolve file references and content, this function returns any discovered Packages after analyzing the catalog source.
func (c *Cataloger) Catalog(resolver file.Resolver) ([]pkg.Package, []artifact.Relationship, error) { func (c *Cataloger) Catalog(resolver file.Resolver) ([]pkg.Package, []artifact.Relationship, error) {
var packages []pkg.Package var packages []pkg.Package
@ -53,12 +46,11 @@ func (c *Cataloger) Catalog(resolver file.Resolver) ([]pkg.Package, []artifact.R
internal.CloseAndLogError(contentReader, location.AccessPath) internal.CloseAndLogError(contentReader, location.AccessPath)
if err != nil { if err != nil {
// TODO: should we fail? or only log? // TODO: should we fail? or only log?
log.Warnf("cataloger '%s' failed to parse entries at location=%+v: %+v", c.upstreamCataloger, location, err) log.Warnf("cataloger failed to parse entries at location=%+v: %+v", location, err)
continue continue
} }
for _, p := range discoveredPackages { for _, p := range discoveredPackages {
p.FoundBy = c.upstreamCataloger
p.Locations = append(p.Locations, location) p.Locations = append(p.Locations, location)
p.SetID() p.SetID()

View File

@ -14,8 +14,6 @@ import (
"github.com/anchore/syft/syft/pkg" "github.com/anchore/syft/syft/pkg"
) )
const catalogerName = "go-module-binary-cataloger"
type Cataloger struct{} type Cataloger struct{}
// NewGoModuleBinaryCataloger returns a new Golang cataloger object. // NewGoModuleBinaryCataloger returns a new Golang cataloger object.
@ -23,11 +21,6 @@ func NewGoModuleBinaryCataloger() *Cataloger {
return &Cataloger{} return &Cataloger{}
} }
// Name returns a string that uniquely describes a cataloger
func (c *Cataloger) Name() string {
return catalogerName
}
// Catalog is given an object to resolve file references and content, this function returns any discovered Packages after analyzing rpm db installation. // Catalog is given an object to resolve file references and content, this function returns any discovered Packages after analyzing rpm db installation.
func (c *Cataloger) Catalog(resolver file.Resolver) ([]pkg.Package, []artifact.Relationship, error) { func (c *Cataloger) Catalog(resolver file.Resolver) ([]pkg.Package, []artifact.Relationship, error) {
var pkgs []pkg.Package var pkgs []pkg.Package

View File

@ -13,5 +13,5 @@ func NewGoModFileCataloger() *generic.Cataloger {
"**/go.mod": parseGoMod, "**/go.mod": parseGoMod,
} }
return generic.NewCataloger(nil, globParsers, "go-mod-file-cataloger") return generic.NewCataloger(nil, globParsers)
} }

View File

@ -30,5 +30,5 @@ func NewJavaCataloger(cfg CatalogerConfig) *generic.Cataloger {
} }
} }
return generic.NewCataloger(nil, globParsers, "java-cataloger") return generic.NewCataloger(nil, globParsers)
} }

View File

@ -13,7 +13,7 @@ func NewJavascriptPackageCataloger() *generic.Cataloger {
"**/package.json": parsePackageJSON, "**/package.json": parsePackageJSON,
} }
return generic.NewCataloger(nil, globParsers, "javascript-package-json-cataloger") return generic.NewCataloger(nil, globParsers)
} }
// NewJavascriptLockCataloger returns a new Javascript cataloger object base on package lock files. // NewJavascriptLockCataloger returns a new Javascript cataloger object base on package lock files.
@ -22,7 +22,7 @@ func NewJavascriptPackageLockCataloger() *generic.Cataloger {
"**/package-lock.json": parsePackageLock, "**/package-lock.json": parsePackageLock,
} }
return generic.NewCataloger(nil, globParsers, "javascript-package-lock-cataloger") return generic.NewCataloger(nil, globParsers)
} }
func NewJavascriptYarnLockCataloger() *generic.Cataloger { func NewJavascriptYarnLockCataloger() *generic.Cataloger {
@ -30,5 +30,5 @@ func NewJavascriptYarnLockCataloger() *generic.Cataloger {
"**/yarn.lock": parseYarnLock, "**/yarn.lock": parseYarnLock,
} }
return generic.NewCataloger(nil, globParsers, "javascript-yarn-lock-cataloger") return generic.NewCataloger(nil, globParsers)
} }

View File

@ -13,7 +13,7 @@ func NewPHPComposerInstalledCataloger() *generic.Cataloger {
"**/installed.json": parseInstalledJSON, "**/installed.json": parseInstalledJSON,
} }
return generic.NewCataloger(nil, globParsers, "php-composer-installed-cataloger") return generic.NewCataloger(nil, globParsers)
} }
// NewPHPComposerLockCataloger returns a new cataloger for PHP composer.lock files. // NewPHPComposerLockCataloger returns a new cataloger for PHP composer.lock files.
@ -22,5 +22,5 @@ func NewPHPComposerLockCataloger() *generic.Cataloger {
"**/composer.lock": parseComposerLock, "**/composer.lock": parseComposerLock,
} }
return generic.NewCataloger(nil, globParsers, "php-composer-lock-cataloger") return generic.NewCataloger(nil, globParsers)
} }

View File

@ -13,7 +13,7 @@ func NewPythonRequirementsCataloger() *generic.Cataloger {
"**/*requirements*.txt": parseRequirementsTxt, "**/*requirements*.txt": parseRequirementsTxt,
} }
return generic.NewCataloger(nil, globParsers, "python-requirements-cataloger") return generic.NewCataloger(nil, globParsers)
} }
func NewPythonPoetryCataloger() *generic.Cataloger { func NewPythonPoetryCataloger() *generic.Cataloger {
@ -21,7 +21,7 @@ func NewPythonPoetryCataloger() *generic.Cataloger {
"**/poetry.lock": parsePoetryLock, "**/poetry.lock": parsePoetryLock,
} }
return generic.NewCataloger(nil, globParsers, "python-poetry-cataloger") return generic.NewCataloger(nil, globParsers)
} }
func NewPythonPipfileCataloger() *generic.Cataloger { func NewPythonPipfileCataloger() *generic.Cataloger {
@ -29,7 +29,7 @@ func NewPythonPipfileCataloger() *generic.Cataloger {
"**/Pipfile.lock": parsePipfileLock, "**/Pipfile.lock": parsePipfileLock,
} }
return generic.NewCataloger(nil, globParsers, "python-pipfile-cataloger") return generic.NewCataloger(nil, globParsers)
} }
func NewPythonSetupCataloger() *generic.Cataloger { func NewPythonSetupCataloger() *generic.Cataloger {
@ -37,5 +37,5 @@ func NewPythonSetupCataloger() *generic.Cataloger {
"**/setup.py": parseSetup, "**/setup.py": parseSetup,
} }
return generic.NewCataloger(nil, globParsers, "python-setup-cataloger") return generic.NewCataloger(nil, globParsers)
} }

View File

@ -28,11 +28,6 @@ func NewPythonPackageCataloger() *PackageCataloger {
return &PackageCataloger{} return &PackageCataloger{}
} }
// Name returns a string that uniquely describes a cataloger
func (c *PackageCataloger) Name() string {
return "python-package-cataloger"
}
// Catalog is given an object to resolve file references and content, this function returns any discovered Packages after analyzing python egg and wheel installations. // Catalog is given an object to resolve file references and content, this function returns any discovered Packages after analyzing python egg and wheel installations.
func (c *PackageCataloger) Catalog(resolver file.Resolver) ([]pkg.Package, []artifact.Relationship, error) { func (c *PackageCataloger) Catalog(resolver file.Resolver) ([]pkg.Package, []artifact.Relationship, error) {
var fileMatches []file.Location var fileMatches []file.Location
@ -79,7 +74,6 @@ func (c *PackageCataloger) catalogEggOrWheel(resolver file.Resolver, metadataLoc
p := &pkg.Package{ p := &pkg.Package{
Name: metadata.Name, Name: metadata.Name,
Version: metadata.Version, Version: metadata.Version,
FoundBy: c.Name(),
Locations: sources, Locations: sources,
Licenses: licenses, Licenses: licenses,
Language: pkg.Python, Language: pkg.Python,

View File

@ -13,8 +13,6 @@ import (
"github.com/anchore/syft/syft/pkg" "github.com/anchore/syft/syft/pkg"
) )
const catalogerName = "rpmdb-cataloger"
type Cataloger struct{} type Cataloger struct{}
// NewRpmdbCataloger returns a new RPM DB cataloger object. // NewRpmdbCataloger returns a new RPM DB cataloger object.
@ -22,11 +20,6 @@ func NewRpmdbCataloger() *Cataloger {
return &Cataloger{} return &Cataloger{}
} }
// Name returns a string that uniquely describes a cataloger
func (c *Cataloger) Name() string {
return catalogerName
}
// Catalog is given an object to resolve file references and content, this function returns any discovered Packages after analyzing rpm db installation. // Catalog is given an object to resolve file references and content, this function returns any discovered Packages after analyzing rpm db installation.
func (c *Cataloger) Catalog(resolver file.Resolver) ([]pkg.Package, []artifact.Relationship, error) { func (c *Cataloger) Catalog(resolver file.Resolver) ([]pkg.Package, []artifact.Relationship, error) {
fileMatches, err := resolver.FilesByGlob(pkg.RpmDBGlob) fileMatches, err := resolver.FilesByGlob(pkg.RpmDBGlob)

View File

@ -63,7 +63,6 @@ func parseRpmDB(resolver file.PathResolver, dbLocation file.Location, reader io.
Name: entry.Name, Name: entry.Name,
Version: toELVersion(metadata), Version: toELVersion(metadata),
Locations: []file.Location{dbLocation}, Locations: []file.Location{dbLocation},
FoundBy: catalogerName,
Type: pkg.RpmPkg, Type: pkg.RpmPkg,
MetadataType: pkg.RpmdbMetadataType, MetadataType: pkg.RpmdbMetadataType,
Metadata: metadata, Metadata: metadata,

View File

@ -13,7 +13,7 @@ func NewGemFileLockCataloger() *generic.Cataloger {
"**/Gemfile.lock": parseGemFileLockEntries, "**/Gemfile.lock": parseGemFileLockEntries,
} }
return generic.NewCataloger(nil, globParsers, "ruby-gemfile-cataloger") return generic.NewCataloger(nil, globParsers)
} }
// NewGemSpecCataloger returns a new Bundler cataloger object tailored for detecting installations of gems (e.g. Gemspec). // NewGemSpecCataloger returns a new Bundler cataloger object tailored for detecting installations of gems (e.g. Gemspec).
@ -22,5 +22,5 @@ func NewGemSpecCataloger() *generic.Cataloger {
"**/specifications/**/*.gemspec": parseGemSpecEntries, "**/specifications/**/*.gemspec": parseGemSpecEntries,
} }
return generic.NewCataloger(nil, globParsers, "ruby-gemspec-cataloger") return generic.NewCataloger(nil, globParsers)
} }

View File

@ -13,5 +13,5 @@ func NewCargoLockCataloger() *generic.Cataloger {
"**/Cargo.lock": parseCargoLock, "**/Cargo.lock": parseCargoLock,
} }
return generic.NewCataloger(nil, globParsers, "rust-cataloger") return generic.NewCataloger(nil, globParsers)
} }

View File

@ -2,11 +2,13 @@ package syft
import ( import (
"crypto" "crypto"
"fmt"
"github.com/anchore/syft/syft/cataloger" "github.com/anchore/syft/syft/cataloger"
"github.com/anchore/syft/syft/cataloger/files/fileclassifier" "github.com/anchore/syft/syft/cataloger/files/fileclassifier"
"github.com/anchore/syft/syft/cataloger/files/secrets" "github.com/anchore/syft/syft/cataloger/files/secrets"
"github.com/anchore/syft/syft/pkg" "github.com/anchore/syft/syft/pkg"
"github.com/anchore/syft/syft/source" "github.com/anchore/syft/syft/source"
"strings"
) )
type CatalogingOption func(*source.Source, *CatalogingConfig) error type CatalogingOption func(*source.Source, *CatalogingConfig) error
@ -47,30 +49,87 @@ func WithToolConfiguration(c interface{}) CatalogingOption {
} }
} }
func WithCataloger(id cataloger.ID, c pkg.Cataloger) CatalogingOption { func WithPackageCataloger(id cataloger.ID, c pkg.Cataloger) CatalogingOption {
return func(_ *source.Source, config *CatalogingConfig) error { return func(_ *source.Source, config *CatalogingConfig) error {
if config.availableTasks == nil { if config.availableTasks == nil {
config.availableTasks = newTaskCollection() var err error
config.availableTasks, err = newTaskCollection()
if err != nil {
return err
}
} }
var cfg CatalogingConfig gen := func(id cataloger.ID, cfg CatalogingConfig) (task, error) {
if config != nil { return newPkgCatalogerTask(id, cfg, c), nil
cfg = *config
} }
config.EnabledCatalogers = append(config.EnabledCatalogers, id)
return config.availableTasks.add(pkgCatalogerTask{ return config.availableTasks.add(string(id), gen)
id: id,
cataloger: c,
config: cfg,
})
} }
} }
func WithDefaultCatalogers() CatalogingOption { func WithDefaultCatalogers() CatalogingOption {
return func(src *source.Source, config *CatalogingConfig) error { return func(src *source.Source, config *CatalogingConfig) error {
if config.availableTasks == nil {
var err error
config.availableTasks, err = newTaskCollection()
if err != nil {
return err
}
}
// override any previously added catalogers // override any previously added catalogers
config.availableTasks = newTaskCollection() tc := config.availableTasks
config.EnabledCatalogers = nil if len(config.EnabledCatalogers) == 0 {
switch src.Metadata.Scheme {
case source.ImageType:
config.EnabledCatalogers = tc.withLabels(packageTaskLabel, installedTaskLabel)
case source.FileType:
config.EnabledCatalogers = tc.all()
case source.DirectoryType:
// TODO: it looks like gemspec was left out on main, is this intentional? if so it's not accounted for here...
config.EnabledCatalogers = tc.withLabels(packageTaskLabel)
}
}
return nil
}
}
func WithCatalogers(catalogers ...string) CatalogingOption {
return func(src *source.Source, config *CatalogingConfig) error {
if config.availableTasks == nil {
var err error
config.availableTasks, err = newTaskCollection()
if err != nil {
return err
}
}
// override any previously added catalogers
for _, q := range catalogers {
var ids []cataloger.ID
isAdditive := strings.HasPrefix(q, "+")
if isAdditive {
ids = config.availableTasks.query(strings.TrimPrefix(q, "+"))
} else {
ids = config.availableTasks.query(q)
}
if len(ids) == 0 {
return fmt.Errorf("cataloger selection invalid: %q", q)
}
if isAdditive && len(config.EnabledCatalogers) == 0 {
// stick in the default set of catalogers first
if err := WithDefaultCatalogers()(src, config); err != nil {
return fmt.Errorf("unable to set default catalogers: %w", err)
}
}
config.EnabledCatalogers = append(config.EnabledCatalogers, ids...)
}
return nil return nil
} }
} }

View File

@ -9,8 +9,6 @@ import (
// contents for the purpose of discovering Packages. Each concrete implementation should focus on discovering Packages // contents for the purpose of discovering Packages. Each concrete implementation should focus on discovering Packages
// for a specific Package Type or ecosystem. // for a specific Package Type or ecosystem.
type Cataloger interface { type Cataloger interface {
// Name returns a string that uniquely describes a cataloger
Name() string
// Catalog is given an object to resolve file references and content, this function returns any discovered Packages after analyzing the catalog source. // Catalog is given an object to resolve file references and content, this function returns any discovered Packages after analyzing the catalog source.
Catalog(resolver file.Resolver) ([]Package, []artifact.Relationship, error) Catalog(resolver file.Resolver) ([]Package, []artifact.Relationship, error)
} }

View File

@ -10,7 +10,9 @@ import (
const ( const (
packageTaskLabel = "package" packageTaskLabel = "package"
packagesTaskLabel = "packages"
fileTaskLabel = "file" fileTaskLabel = "file"
filesTaskLabel = "files"
osTaskLabel = "os" osTaskLabel = "os"
languageTaskLabel = "language" languageTaskLabel = "language"
installedTaskLabel = "installed" installedTaskLabel = "installed"
@ -18,36 +20,24 @@ const (
) )
type taskCollection struct { type taskCollection struct {
taskByName map[string]task // name -> generator taskConstructorByName map[string]taskGenerator // name -> generator
namesByLabel map[string][]string // label -> names namesByLabel map[string][]string // label -> names
} }
func newTaskCollection() *taskCollection { func newTaskCollection() (*taskCollection, error) {
return &taskCollection{ c := &taskCollection{
taskByName: make(map[string]task), taskConstructorByName: make(map[string]taskGenerator),
namesByLabel: make(map[string][]string), namesByLabel: make(map[string][]string),
} }
return c, c.addAllCatalogers()
} }
func (c *taskCollection) add(t task, labels ...string) error { func (c *taskCollection) add(name string, g taskGenerator, labels ...string) error {
var name string if _, exists := c.taskConstructorByName[name]; exists {
switch v := t.(type) { return fmt.Errorf("task constructor already exists: %q", name)
case pkgCatalogerTask:
name = string(v.id)
case catalogerTask:
name = string(v.id)
default:
if len(labels) == 0 {
return fmt.Errorf("no ID found for generic task")
}
name = labels[0]
} }
if _, exists := c.taskByName[name]; exists { c.taskConstructorByName[name] = g
return fmt.Errorf("task already exists: %q", name)
}
c.taskByName[name] = t
labelSet := strset.New(labels...) labelSet := strset.New(labels...)
labelSet.Add(name) labelSet.Add(name)
@ -57,118 +47,134 @@ func (c *taskCollection) add(t task, labels ...string) error {
return nil return nil
} }
func (c *taskCollection) addAllCatalogers(config CatalogingConfig) error { func (c *taskCollection) addAllCatalogers() error {
for _, d := range []struct { for _, d := range []struct {
id cataloger.ID
generator taskGenerator generator taskGenerator
labels []string labels []string
}{ }{
{ {
id: cataloger.ApkDBID,
generator: newAPKDBCatalogingTask, generator: newAPKDBCatalogingTask,
labels: []string{packageTaskLabel, osTaskLabel, installedTaskLabel, "alpine", "apk", "apkdb"}, labels: []string{packageTaskLabel, packagesTaskLabel, osTaskLabel, installedTaskLabel, "alpine", "apk", "apkdb"},
}, },
{ {
id: cataloger.DpkgID,
generator: newDPKGCatalogingTask, generator: newDPKGCatalogingTask,
labels: []string{packageTaskLabel, osTaskLabel, installedTaskLabel, "debian", "dpkg", "deb", "dpkgdb"}, labels: []string{packageTaskLabel, packagesTaskLabel, osTaskLabel, installedTaskLabel, "debian", "dpkg", "deb", "dpkgdb"},
}, },
{ {
id: cataloger.RpmDBID,
generator: newRPMDBCatalogingTask, generator: newRPMDBCatalogingTask,
labels: []string{packageTaskLabel, osTaskLabel, installedTaskLabel, "redhat", "rhel", "centos", "rpm", "rpmdb"}, labels: []string{packageTaskLabel, packagesTaskLabel, osTaskLabel, installedTaskLabel, "redhat", "rhel", "centos", "rpm", "rpmdb"},
}, },
{ {
id: cataloger.RubyGemspecID,
generator: newRubyGemSpecCatalogingTask, generator: newRubyGemSpecCatalogingTask,
labels: []string{packageTaskLabel, languageTaskLabel, installedTaskLabel, "ruby", "gemspec", "gem"}, labels: []string{packageTaskLabel, packagesTaskLabel, languageTaskLabel, installedTaskLabel, "ruby", "gemspec", "gem"},
}, },
{ {
id: cataloger.RubyGemfileLockID,
generator: newRubyGemFileLockCatalogingTask, generator: newRubyGemFileLockCatalogingTask,
labels: []string{packageTaskLabel, languageTaskLabel, declaredTaskLabel, "ruby", "gemfile", "gem", "gemfile.lock"}, labels: []string{packageTaskLabel, packagesTaskLabel, languageTaskLabel, declaredTaskLabel, "ruby", "gemfile", "gem", "gemfile.lock"},
}, },
{ {
id: cataloger.PythonPackageID,
generator: newPythonPackageCatalogingTask, generator: newPythonPackageCatalogingTask,
labels: []string{packageTaskLabel, languageTaskLabel, installedTaskLabel, "python", "egg", "wheel"}, labels: []string{packageTaskLabel, packagesTaskLabel, languageTaskLabel, installedTaskLabel, "python", "egg", "wheel"},
}, },
{ {
id: cataloger.PythonRequirementsID,
generator: newPythonRequirementsCatalogingTask, generator: newPythonRequirementsCatalogingTask,
labels: []string{packageTaskLabel, languageTaskLabel, declaredTaskLabel, "python", "requirements", "requirements.txt"}, labels: []string{packageTaskLabel, packagesTaskLabel, languageTaskLabel, declaredTaskLabel, "python", "requirements", "requirements.txt"},
}, },
{ {
id: cataloger.PythonPoetryID,
generator: newPythonPoetryCatalogingTask, generator: newPythonPoetryCatalogingTask,
labels: []string{packageTaskLabel, languageTaskLabel, declaredTaskLabel, "python", "poetry", "poetry.lock"}, labels: []string{packageTaskLabel, packagesTaskLabel, languageTaskLabel, declaredTaskLabel, "python", "poetry", "poetry.lock"},
}, },
{ {
id: cataloger.PythonSetupID,
generator: newPythonSetupCatalogingTask, generator: newPythonSetupCatalogingTask,
labels: []string{packageTaskLabel, languageTaskLabel, declaredTaskLabel, "python", "setup", "setup.py"}, labels: []string{packageTaskLabel, packagesTaskLabel, languageTaskLabel, declaredTaskLabel, "python", "setup", "setup.py"},
}, },
{ {
id: cataloger.PythonPipFileID,
generator: newPythonPipfileCatalogingTask, generator: newPythonPipfileCatalogingTask,
labels: []string{packageTaskLabel, languageTaskLabel, declaredTaskLabel, "python", "pip", "pipfile"}, labels: []string{packageTaskLabel, packagesTaskLabel, languageTaskLabel, declaredTaskLabel, "python", "pip", "pipfile"},
}, },
{ {
id: cataloger.JavascriptPackageJSONID,
generator: newJavascriptPackageJSONCatalogingTask, generator: newJavascriptPackageJSONCatalogingTask,
labels: []string{packageTaskLabel, languageTaskLabel, installedTaskLabel, "javascript", "node", "package.json"}, labels: []string{packageTaskLabel, packagesTaskLabel, languageTaskLabel, installedTaskLabel, "javascript", "node", "package.json"},
}, },
{ {
id: cataloger.JavascriptPackageLockID,
generator: newJavascriptPackageLockCatalogingTask, generator: newJavascriptPackageLockCatalogingTask,
labels: []string{packageTaskLabel, languageTaskLabel, declaredTaskLabel, "javascript", "node", "package-lock.json"}, labels: []string{packageTaskLabel, packagesTaskLabel, languageTaskLabel, declaredTaskLabel, "javascript", "node", "package-lock.json"},
}, },
{ {
id: cataloger.JavaScriptYarnLockID,
generator: newJavascriptYarnLockCatalogingTask, generator: newJavascriptYarnLockCatalogingTask,
labels: []string{packageTaskLabel, languageTaskLabel, declaredTaskLabel, "javascript", "node", "yarn", "yarn.lock"}, labels: []string{packageTaskLabel, packagesTaskLabel, languageTaskLabel, declaredTaskLabel, "javascript", "node", "yarn", "yarn.lock"},
}, },
{ {
id: cataloger.JavaArchiveID,
generator: newJavaCatalogingTask, generator: newJavaCatalogingTask,
labels: []string{packageTaskLabel, languageTaskLabel, installedTaskLabel, "java", "maven", "jar", "war", "ear", "jenkins", "hudson", "hpi", "jpi", "par", "sar", "lpkg"}, labels: []string{packageTaskLabel, packagesTaskLabel, languageTaskLabel, installedTaskLabel, "java", "maven", "jar", "war", "ear", "jenkins", "hudson", "hpi", "jpi", "par", "sar", "lpkg"},
}, },
{ {
id: cataloger.GoModID,
generator: newGolangModuleCatalogingTask, generator: newGolangModuleCatalogingTask,
labels: []string{packageTaskLabel, languageTaskLabel, declaredTaskLabel, "go", "golang", "go-module", "go.mod"}, labels: []string{packageTaskLabel, packagesTaskLabel, languageTaskLabel, declaredTaskLabel, "go", "golang", "go-module", "go.mod"},
}, },
{ {
id: cataloger.GoBinaryID,
generator: newGolangBinaryCatalogingTask, generator: newGolangBinaryCatalogingTask,
labels: []string{packageTaskLabel, languageTaskLabel, installedTaskLabel, "go", "golang", "go-module", "binary"}, labels: []string{packageTaskLabel, packagesTaskLabel, languageTaskLabel, installedTaskLabel, "go", "golang", "go-module", "binary"},
}, },
{ {
id: cataloger.RustCargoLockID,
generator: newRustCargoLockCatalogingTask, generator: newRustCargoLockCatalogingTask,
labels: []string{packageTaskLabel, languageTaskLabel, declaredTaskLabel, "rust", "cargo", "cargo.lock"}, labels: []string{packageTaskLabel, packagesTaskLabel, languageTaskLabel, declaredTaskLabel, "rust", "cargo", "cargo.lock"},
}, },
{ {
id: cataloger.PHPInstalledJSONID,
generator: newPHPInstalledCatalogingTask, generator: newPHPInstalledCatalogingTask,
labels: []string{packageTaskLabel, languageTaskLabel, installedTaskLabel, "php", "composer", "installed.json"}, labels: []string{packageTaskLabel, packagesTaskLabel, languageTaskLabel, installedTaskLabel, "php", "composer", "installed.json"},
}, },
{ {
id: cataloger.PHPComposerLockID,
generator: newPHPComposerLockCatalogingTask, generator: newPHPComposerLockCatalogingTask,
labels: []string{packageTaskLabel, languageTaskLabel, declaredTaskLabel, "php", "composer", "composer.lock"}, labels: []string{packageTaskLabel, packagesTaskLabel, languageTaskLabel, declaredTaskLabel, "php", "composer", "composer.lock"},
}, },
{ {
id: cataloger.FileMetadataID,
generator: newFileMetadataCatalogingTask, generator: newFileMetadataCatalogingTask,
labels: []string{fileTaskLabel}, labels: []string{fileTaskLabel, filesTaskLabel},
}, },
{ {
id: cataloger.FileDigestsID,
generator: newFileDigestsCatalogingTask, generator: newFileDigestsCatalogingTask,
labels: []string{fileTaskLabel, "digests", "digest", "file-digests"}, labels: []string{fileTaskLabel, filesTaskLabel, "digests", "digest", "file-digests"},
}, },
{ {
id: cataloger.SecretsID,
generator: newSecretsCatalogingTask, generator: newSecretsCatalogingTask,
labels: []string{"secrets"}, labels: []string{"secrets"},
}, },
{ {
id: cataloger.FileClassifierID,
generator: newFileClassifierTask, generator: newFileClassifierTask,
labels: []string{fileTaskLabel, "classifier"}, labels: []string{fileTaskLabel, filesTaskLabel, "classifier"},
}, },
{ {
id: cataloger.FileContentsID,
generator: newFileContentsCatalogingTask, generator: newFileContentsCatalogingTask,
labels: []string{fileTaskLabel, "contents", "content", "file-contents"}, labels: []string{fileTaskLabel, filesTaskLabel, "contents", "content", "file-contents"},
}, },
} { } {
t, err := d.generator(config) if err := c.add(string(d.id), d.generator, d.labels...); err != nil {
if err != nil {
return err
}
if t == nil {
continue
}
if err := c.add(t, d.labels...); err != nil {
return err return err
} }
} }
@ -178,7 +184,7 @@ func (c *taskCollection) addAllCatalogers(config CatalogingConfig) error {
func (c taskCollection) query(q string) []cataloger.ID { func (c taskCollection) query(q string) []cataloger.ID {
fields := strings.FieldsFunc(q, func(r rune) bool { fields := strings.FieldsFunc(q, func(r rune) bool {
switch r { switch r {
case '+', ',', '&': case '+', '&':
return true return true
} }
return false return false
@ -189,7 +195,7 @@ func (c taskCollection) query(q string) []cataloger.ID {
func (c taskCollection) all() []cataloger.ID { func (c taskCollection) all() []cataloger.ID {
var ret []cataloger.ID var ret []cataloger.ID
for k := range c.taskByName { for k := range c.taskConstructorByName {
ret = append(ret, cataloger.ID(k)) ret = append(ret, cataloger.ID(k))
} }
@ -221,13 +227,24 @@ func (c taskCollection) withLabels(q ...string) []cataloger.ID {
return ret return ret
} }
func (c taskCollection) tasks(ids ...cataloger.ID) (ts []task) { func (c taskCollection) tasks(config CatalogingConfig, ids ...cataloger.ID) ([]task, error) {
var ts []task
for _, id := range ids { for _, id := range ids {
t, exists := c.taskByName[string(id)] g, exists := c.taskConstructorByName[string(id)]
if !exists { if !exists {
continue continue
} }
t, err := g(id, config)
if err != nil {
return nil, fmt.Errorf("unable to construct task %q: %w", id, err)
}
if t == nil {
continue
}
ts = append(ts, t) ts = append(ts, t)
} }
return ts return ts, nil
} }

View File

@ -2,6 +2,7 @@ package syft
import ( import (
"fmt" "fmt"
"github.com/anchore/syft/internal/log"
"github.com/anchore/syft/syft/cataloger" "github.com/anchore/syft/syft/cataloger"
"github.com/anchore/syft/syft/cataloger/files/fileclassifier" "github.com/anchore/syft/syft/cataloger/files/fileclassifier"
"github.com/anchore/syft/syft/cataloger/files/filecontents" "github.com/anchore/syft/syft/cataloger/files/filecontents"
@ -28,7 +29,7 @@ import (
"github.com/anchore/syft/syft/source" "github.com/anchore/syft/syft/source"
) )
type taskGenerator func(CatalogingConfig) (task, error) type taskGenerator func(cataloger.ID, CatalogingConfig) (task, error)
type task interface { type task interface {
Run(*sbom.Artifacts, *source.Source) ([]artifact.Relationship, error) Run(*sbom.Artifacts, *source.Source) ([]artifact.Relationship, error)
@ -53,6 +54,14 @@ type pkgCatalogerTask struct {
config CatalogingConfig config CatalogingConfig
} }
func newPkgCatalogerTask(id cataloger.ID, config CatalogingConfig, c pkg.Cataloger) pkgCatalogerTask {
return pkgCatalogerTask{
id: id,
cataloger: c,
config: config,
}
}
func (t pkgCatalogerTask) Run(artifacts *sbom.Artifacts, src *source.Source) ([]artifact.Relationship, error) { func (t pkgCatalogerTask) Run(artifacts *sbom.Artifacts, src *source.Source) ([]artifact.Relationship, error) {
resolver, err := src.FileResolver(t.config.DefaultScope) resolver, err := src.FileResolver(t.config.DefaultScope)
if err != nil { if err != nil {
@ -90,166 +99,96 @@ func newIdentifyDistroTask(config CatalogingConfig) (task, error) {
}, nil }, nil
} }
func newAPKDBCatalogingTask(config CatalogingConfig) (task, error) { func newAPKDBCatalogingTask(id cataloger.ID, config CatalogingConfig) (task, error) {
return pkgCatalogerTask{ return newPkgCatalogerTask(id, config, apkdb.NewApkdbCataloger()), nil
id: cataloger.ApkDBID,
cataloger: apkdb.NewApkdbCataloger(),
config: config,
}, nil
} }
func newDPKGCatalogingTask(config CatalogingConfig) (task, error) { func newDPKGCatalogingTask(id cataloger.ID, config CatalogingConfig) (task, error) {
return pkgCatalogerTask{ return newPkgCatalogerTask(id, config, deb.NewDpkgdbCataloger()), nil
id: cataloger.DpkgID,
cataloger: deb.NewDpkgdbCataloger(),
config: config,
}, nil
} }
func newGolangBinaryCatalogingTask(config CatalogingConfig) (task, error) { func newGolangBinaryCatalogingTask(id cataloger.ID, config CatalogingConfig) (task, error) {
return pkgCatalogerTask{ return newPkgCatalogerTask(id, config, golang.NewGoModuleBinaryCataloger()), nil
id: cataloger.GoBinaryID,
cataloger: golang.NewGoModuleBinaryCataloger(),
config: config,
}, nil
} }
func newGolangModuleCatalogingTask(config CatalogingConfig) (task, error) { func newGolangModuleCatalogingTask(id cataloger.ID, config CatalogingConfig) (task, error) {
return pkgCatalogerTask{ return newPkgCatalogerTask(id, config, golang.NewGoModFileCataloger()), nil
id: cataloger.GoModID,
cataloger: golang.NewGoModFileCataloger(),
config: config,
}, nil
} }
func newJavaCatalogingTask(config CatalogingConfig) (task, error) { func newJavaCatalogingTask(id cataloger.ID, config CatalogingConfig) (task, error) {
return pkgCatalogerTask{ return newPkgCatalogerTask(
id: cataloger.JavaArchiveID, id,
cataloger: java.NewJavaCataloger(java.CatalogerConfig{ config,
java.NewJavaCataloger(
java.CatalogerConfig{
SearchUnindexedArchives: config.PackageSearch.IncludeUnindexedArchives, SearchUnindexedArchives: config.PackageSearch.IncludeUnindexedArchives,
SearchIndexedArchives: config.PackageSearch.IncludeIndexedArchives, SearchIndexedArchives: config.PackageSearch.IncludeIndexedArchives,
}), },
config: config, ),
}, nil ), nil
} }
func newJavascriptPackageJSONCatalogingTask(config CatalogingConfig) (task, error) { func newJavascriptPackageJSONCatalogingTask(id cataloger.ID, config CatalogingConfig) (task, error) {
return pkgCatalogerTask{ return newPkgCatalogerTask(id, config, javascript.NewJavascriptPackageCataloger()), nil
id: cataloger.JavascriptPackageJSONID,
cataloger: javascript.NewJavascriptPackageCataloger(),
config: config,
}, nil
} }
func newJavascriptPackageLockCatalogingTask(config CatalogingConfig) (task, error) { func newJavascriptPackageLockCatalogingTask(id cataloger.ID, config CatalogingConfig) (task, error) {
return pkgCatalogerTask{ return newPkgCatalogerTask(id, config, javascript.NewJavascriptPackageLockCataloger()), nil
id: cataloger.JavascriptPackageLockID,
cataloger: javascript.NewJavascriptPackageLockCataloger(),
config: config,
}, nil
} }
func newJavascriptYarnLockCatalogingTask(config CatalogingConfig) (task, error) { func newJavascriptYarnLockCatalogingTask(id cataloger.ID, config CatalogingConfig) (task, error) {
return pkgCatalogerTask{ return newPkgCatalogerTask(id, config, javascript.NewJavascriptYarnLockCataloger()), nil
id: cataloger.JavaScriptYarnLockID,
cataloger: javascript.NewJavascriptYarnLockCataloger(),
config: config,
}, nil
} }
func newPHPComposerLockCatalogingTask(config CatalogingConfig) (task, error) { func newPHPComposerLockCatalogingTask(id cataloger.ID, config CatalogingConfig) (task, error) {
return pkgCatalogerTask{ return newPkgCatalogerTask(id, config, php.NewPHPComposerLockCataloger()), nil
id: cataloger.PHPComposerLockID,
cataloger: php.NewPHPComposerLockCataloger(),
config: config,
}, nil
} }
func newPHPInstalledCatalogingTask(config CatalogingConfig) (task, error) { func newPHPInstalledCatalogingTask(id cataloger.ID, config CatalogingConfig) (task, error) {
return pkgCatalogerTask{ return newPkgCatalogerTask(id, config, php.NewPHPComposerInstalledCataloger()), nil
id: cataloger.PHPInstalledJSONID,
cataloger: php.NewPHPComposerInstalledCataloger(),
config: config,
}, nil
} }
func newPythonPackageCatalogingTask(config CatalogingConfig) (task, error) { func newPythonPackageCatalogingTask(id cataloger.ID, config CatalogingConfig) (task, error) {
return pkgCatalogerTask{ return newPkgCatalogerTask(id, config, python.NewPythonPackageCataloger()), nil
id: cataloger.PythonPackageID,
cataloger: python.NewPythonPackageCataloger(),
config: config,
}, nil
} }
func newPythonRequirementsCatalogingTask(config CatalogingConfig) (task, error) { func newPythonRequirementsCatalogingTask(id cataloger.ID, config CatalogingConfig) (task, error) {
return pkgCatalogerTask{ return newPkgCatalogerTask(id, config, python.NewPythonRequirementsCataloger()), nil
id: cataloger.PythonRequirementsID,
cataloger: python.NewPythonRequirementsCataloger(),
config: config,
}, nil
} }
func newPythonPoetryCatalogingTask(config CatalogingConfig) (task, error) { func newPythonPoetryCatalogingTask(id cataloger.ID, config CatalogingConfig) (task, error) {
return pkgCatalogerTask{ return newPkgCatalogerTask(id, config, python.NewPythonPoetryCataloger()), nil
id: cataloger.PythonPoetryID,
cataloger: python.NewPythonPoetryCataloger(),
config: config,
}, nil
} }
func newPythonPipfileCatalogingTask(config CatalogingConfig) (task, error) { func newPythonPipfileCatalogingTask(id cataloger.ID, config CatalogingConfig) (task, error) {
return pkgCatalogerTask{ return newPkgCatalogerTask(id, config, python.NewPythonPipfileCataloger()), nil
id: cataloger.PythonPipFileID,
cataloger: python.NewPythonPipfileCataloger(),
config: config,
}, nil
} }
func newPythonSetupCatalogingTask(config CatalogingConfig) (task, error) { func newPythonSetupCatalogingTask(id cataloger.ID, config CatalogingConfig) (task, error) {
return pkgCatalogerTask{ return newPkgCatalogerTask(id, config, python.NewPythonSetupCataloger()), nil
id: cataloger.PythonSetupID,
cataloger: python.NewPythonSetupCataloger(),
config: config,
}, nil
} }
func newRPMDBCatalogingTask(config CatalogingConfig) (task, error) { func newRPMDBCatalogingTask(id cataloger.ID, config CatalogingConfig) (task, error) {
return pkgCatalogerTask{ return newPkgCatalogerTask(id, config, rpmdb.NewRpmdbCataloger()), nil
id: cataloger.RpmDBID,
cataloger: rpmdb.NewRpmdbCataloger(),
config: config,
}, nil
} }
func newRubyGemFileLockCatalogingTask(config CatalogingConfig) (task, error) { func newRubyGemFileLockCatalogingTask(id cataloger.ID, config CatalogingConfig) (task, error) {
return pkgCatalogerTask{ return newPkgCatalogerTask(id, config, ruby.NewGemFileLockCataloger()), nil
id: cataloger.RubyGemfileLockID,
cataloger: ruby.NewGemFileLockCataloger(),
config: config,
}, nil
} }
func newRubyGemSpecCatalogingTask(config CatalogingConfig) (task, error) { func newRubyGemSpecCatalogingTask(id cataloger.ID, config CatalogingConfig) (task, error) {
return pkgCatalogerTask{ return newPkgCatalogerTask(id, config, ruby.NewGemSpecCataloger()), nil
id: cataloger.RubyGemspecID,
cataloger: ruby.NewGemSpecCataloger(),
config: config,
}, nil
} }
func newRustCargoLockCatalogingTask(config CatalogingConfig) (task, error) { func newRustCargoLockCatalogingTask(id cataloger.ID, config CatalogingConfig) (task, error) {
return pkgCatalogerTask{ return newPkgCatalogerTask(id, config, rust.NewCargoLockCataloger()), nil
id: cataloger.RustCargoLockID,
cataloger: rust.NewCargoLockCataloger(),
config: config,
}, nil
} }
func newFileMetadataCatalogingTask(config CatalogingConfig) (task, error) { func newFileMetadataCatalogingTask(id cataloger.ID, config CatalogingConfig) (task, error) {
c := filemetadata.NewCataloger() c := filemetadata.NewCataloger()
return catalogerTask{ return catalogerTask{
id: cataloger.FileMetadataID, id: id,
genericTask: genericTask{ genericTask: genericTask{
run: func(results *sbom.Artifacts, src *source.Source) ([]artifact.Relationship, error) { run: func(results *sbom.Artifacts, src *source.Source) ([]artifact.Relationship, error) {
resolver, err := src.FileResolver(config.DefaultScope) resolver, err := src.FileResolver(config.DefaultScope)
@ -268,8 +207,9 @@ func newFileMetadataCatalogingTask(config CatalogingConfig) (task, error) {
}, nil }, nil
} }
func newFileDigestsCatalogingTask(config CatalogingConfig) (task, error) { func newFileDigestsCatalogingTask(id cataloger.ID, config CatalogingConfig) (task, error) {
if len(config.DigestHashes) == 0 { if len(config.DigestHashes) == 0 {
log.Warn("using file-digest cataloger with no file digest algorithms configured")
return nil, nil return nil, nil
} }
@ -279,7 +219,7 @@ func newFileDigestsCatalogingTask(config CatalogingConfig) (task, error) {
} }
return catalogerTask{ return catalogerTask{
id: cataloger.FileDigestsID, id: id,
genericTask: genericTask{ genericTask: genericTask{
run: func(results *sbom.Artifacts, src *source.Source) ([]artifact.Relationship, error) { run: func(results *sbom.Artifacts, src *source.Source) ([]artifact.Relationship, error) {
resolver, err := src.FileResolver(config.DefaultScope) resolver, err := src.FileResolver(config.DefaultScope)
@ -298,8 +238,9 @@ func newFileDigestsCatalogingTask(config CatalogingConfig) (task, error) {
}, nil }, nil
} }
func newFileContentsCatalogingTask(config CatalogingConfig) (task, error) { func newFileContentsCatalogingTask(id cataloger.ID, config CatalogingConfig) (task, error) {
if len(config.ContentsSearch.Globs) == 0 { if len(config.ContentsSearch.Globs) == 0 {
log.Warn("using file-content cataloger with no content file paths/globs configured")
return nil, nil return nil, nil
} }
@ -309,7 +250,7 @@ func newFileContentsCatalogingTask(config CatalogingConfig) (task, error) {
} }
return catalogerTask{ return catalogerTask{
id: cataloger.FileContentsID, id: id,
genericTask: genericTask{ genericTask: genericTask{
run: func(results *sbom.Artifacts, src *source.Source) ([]artifact.Relationship, error) { run: func(results *sbom.Artifacts, src *source.Source) ([]artifact.Relationship, error) {
resolver, err := src.FileResolver(config.DefaultScope) resolver, err := src.FileResolver(config.DefaultScope)
@ -328,15 +269,14 @@ func newFileContentsCatalogingTask(config CatalogingConfig) (task, error) {
}, nil }, nil
} }
func newSecretsCatalogingTask(config CatalogingConfig) (task, error) { func newSecretsCatalogingTask(id cataloger.ID, config CatalogingConfig) (task, error) {
c, err := secrets.NewCataloger(config.SecretsSearch) c, err := secrets.NewCataloger(config.SecretsSearch)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return catalogerTask{ return catalogerTask{
id: cataloger.SecretsID, id: id,
genericTask: genericTask{ genericTask: genericTask{
run: func(results *sbom.Artifacts, src *source.Source) ([]artifact.Relationship, error) { run: func(results *sbom.Artifacts, src *source.Source) ([]artifact.Relationship, error) {
resolver, err := src.FileResolver(config.SecretsScope) resolver, err := src.FileResolver(config.SecretsScope)
@ -355,15 +295,14 @@ func newSecretsCatalogingTask(config CatalogingConfig) (task, error) {
}, nil }, nil
} }
func newFileClassifierTask(config CatalogingConfig) (task, error) { func newFileClassifierTask(id cataloger.ID, config CatalogingConfig) (task, error) {
c, err := fileclassifier.NewCataloger(config.FileClassifiers) c, err := fileclassifier.NewCataloger(config.FileClassifiers)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return catalogerTask{ return catalogerTask{
id: cataloger.FileClassifierID, id: id,
genericTask: genericTask{ genericTask: genericTask{
run: func(results *sbom.Artifacts, src *source.Source) ([]artifact.Relationship, error) { run: func(results *sbom.Artifacts, src *source.Source) ([]artifact.Relationship, error) {
resolver, err := src.FileResolver(config.DefaultScope) resolver, err := src.FileResolver(config.DefaultScope)
@ -383,7 +322,6 @@ func newFileClassifierTask(config CatalogingConfig) (task, error) {
} }
func newSynthesizePackageRelationshipsTasks(config CatalogingConfig) (task, error) { func newSynthesizePackageRelationshipsTasks(config CatalogingConfig) (task, error) {
return genericTask{ return genericTask{
run: func(artifacts *sbom.Artifacts, src *source.Source) ([]artifact.Relationship, error) { run: func(artifacts *sbom.Artifacts, src *source.Source) ([]artifact.Relationship, error) {
resolver, err := src.FileResolver(config.DefaultScope) resolver, err := src.FileResolver(config.DefaultScope)