package eventloop import ( "crypto" "fmt" "github.com/anchore/syft/internal/config" "github.com/anchore/syft/syft" "github.com/anchore/syft/syft/artifact" "github.com/anchore/syft/syft/file" "github.com/anchore/syft/syft/sbom" "github.com/anchore/syft/syft/source" ) type Task func(*sbom.Artifacts, *source.Source) ([]artifact.Relationship, error) func Tasks(app *config.Application) ([]Task, error) { var tasks []Task generators := []func(app *config.Application) (Task, error){ generateCatalogPackagesTask, generateCatalogFileMetadataTask, generateCatalogFileDigestsTask, generateCatalogSecretsTask, generateCatalogFileClassificationsTask, generateCatalogContentsTask, } for _, generator := range generators { task, err := generator(app) if err != nil { return nil, err } if task != nil { tasks = append(tasks, task) } } return tasks, nil } func generateCatalogPackagesTask(app *config.Application) (Task, error) { if !app.Package.Cataloger.Enabled { return nil, nil } task := func(results *sbom.Artifacts, src *source.Source) ([]artifact.Relationship, error) { packageCatalog, relationships, theDistro, err := syft.CatalogPackages(src, app.ToCatalogerConfig()) if err != nil { return nil, err } results.PackageCatalog = packageCatalog results.LinuxDistribution = theDistro return relationships, nil } return task, nil } func generateCatalogFileMetadataTask(app *config.Application) (Task, error) { if !app.FileMetadata.Cataloger.Enabled { return nil, nil } metadataCataloger := file.NewMetadataCataloger() task := func(results *sbom.Artifacts, src *source.Source) ([]artifact.Relationship, error) { resolver, err := src.FileResolver(app.FileMetadata.Cataloger.ScopeOpt) if err != nil { return nil, err } result, err := metadataCataloger.Catalog(resolver) if err != nil { return nil, err } results.FileMetadata = result return nil, nil } return task, nil } func generateCatalogFileDigestsTask(app *config.Application) (Task, error) { if !app.FileMetadata.Cataloger.Enabled { return nil, nil } supportedHashAlgorithms := make(map[string]crypto.Hash) for _, h := range []crypto.Hash{ crypto.MD5, crypto.SHA1, crypto.SHA256, } { supportedHashAlgorithms[file.DigestAlgorithmName(h)] = h } var hashes []crypto.Hash for _, hashStr := range app.FileMetadata.Digests { name := file.CleanDigestAlgorithmName(hashStr) hashObj, ok := supportedHashAlgorithms[name] if !ok { return nil, fmt.Errorf("unsupported hash algorithm: %s", hashStr) } hashes = append(hashes, hashObj) } digestsCataloger, err := file.NewDigestsCataloger(hashes) if err != nil { return nil, err } task := func(results *sbom.Artifacts, src *source.Source) ([]artifact.Relationship, error) { resolver, err := src.FileResolver(app.FileMetadata.Cataloger.ScopeOpt) if err != nil { return nil, err } result, err := digestsCataloger.Catalog(resolver) if err != nil { return nil, err } results.FileDigests = result return nil, nil } return task, nil } func generateCatalogSecretsTask(app *config.Application) (Task, error) { if !app.Secrets.Cataloger.Enabled { return nil, nil } patterns, err := file.GenerateSearchPatterns(file.DefaultSecretsPatterns, app.Secrets.AdditionalPatterns, app.Secrets.ExcludePatternNames) if err != nil { return nil, err } secretsCataloger, err := file.NewSecretsCataloger(patterns, app.Secrets.RevealValues, app.Secrets.SkipFilesAboveSize) if err != nil { return nil, err } task := func(results *sbom.Artifacts, src *source.Source) ([]artifact.Relationship, error) { resolver, err := src.FileResolver(app.Secrets.Cataloger.ScopeOpt) if err != nil { return nil, err } result, err := secretsCataloger.Catalog(resolver) if err != nil { return nil, err } results.Secrets = result return nil, nil } return task, nil } func generateCatalogFileClassificationsTask(app *config.Application) (Task, error) { if !app.FileClassification.Cataloger.Enabled { return nil, nil } // TODO: in the future we could expose out the classifiers via configuration classifierCataloger, err := file.NewClassificationCataloger(file.DefaultClassifiers) if err != nil { return nil, err } task := func(results *sbom.Artifacts, src *source.Source) ([]artifact.Relationship, error) { resolver, err := src.FileResolver(app.FileClassification.Cataloger.ScopeOpt) if err != nil { return nil, err } result, err := classifierCataloger.Catalog(resolver) if err != nil { return nil, err } results.FileClassifications = result return nil, nil } return task, nil } func generateCatalogContentsTask(app *config.Application) (Task, error) { if !app.FileContents.Cataloger.Enabled { return nil, nil } contentsCataloger, err := file.NewContentsCataloger(app.FileContents.Globs, app.FileContents.SkipFilesAboveSize) if err != nil { return nil, err } task := func(results *sbom.Artifacts, src *source.Source) ([]artifact.Relationship, error) { resolver, err := src.FileResolver(app.FileContents.Cataloger.ScopeOpt) if err != nil { return nil, err } result, err := contentsCataloger.Catalog(resolver) if err != nil { return nil, err } results.FileContents = result return nil, nil } return task, nil } func RunTask(t Task, a *sbom.Artifacts, src *source.Source, c chan<- artifact.Relationship, errs chan<- error) { defer close(c) relationships, err := t(a, src) if err != nil { errs <- err return } for _, relationship := range relationships { c <- relationship } }