diff --git a/cmd/__debug_bin b/cmd/__debug_bin new file mode 100644 index 000000000..bf5833897 Binary files /dev/null and b/cmd/__debug_bin differ diff --git a/cmd/attest.go b/cmd/attest.go index b2e0e9ff3..560fd075c 100644 --- a/cmd/attest.go +++ b/cmd/attest.go @@ -9,6 +9,7 @@ import ( "os" "strings" + "github.com/anchore/syft/internal/config" "github.com/anchore/syft/internal/formats/cyclonedxjson" "github.com/anchore/syft/internal/formats/spdx22json" "github.com/anchore/syft/internal/formats/syftjson" @@ -84,7 +85,7 @@ var ( defer profile.Start(profile.MemProfile).Stop() } - return attestExec(cmd.Context(), cmd, args) + return attestExec(cmd.Context(), cmd, args, appConfig) }, } ) @@ -128,7 +129,7 @@ func selectPassFunc(keypath string) (cosign.PassFunc, error) { return fn, nil } -func attestExec(ctx context.Context, _ *cobra.Command, args []string) error { +func attestExec(ctx context.Context, _ *cobra.Command, args []string, cfg *config.Application) error { // can only be an image for attestation or OCI DIR userInput := args[0] si, err := source.ParseInput(userInput, appConfig.Platform, false) @@ -180,15 +181,15 @@ func attestExec(ctx context.Context, _ *cobra.Command, args []string) error { defer sv.Close() return eventLoop( - attestationExecWorker(*si, format, predicateType, sv), + attestationExecWorker(*si, cfg, format, predicateType, sv), setupSignals(), eventSubscription, stereoscope.Cleanup, - ui.Select(isVerbose(), appConfig.Quiet)..., + ui.Select(isVerbose(appConfig), appConfig.Quiet)..., ) } -func attestationExecWorker(sourceInput source.Input, format sbom.Format, predicateType string, sv *sign.SignerVerifier) <-chan error { +func attestationExecWorker(sourceInput source.Input, cfg *config.Application, format sbom.Format, predicateType string, sv *sign.SignerVerifier) <-chan error { errs := make(chan error) go func() { defer close(errs) @@ -202,7 +203,7 @@ func attestationExecWorker(sourceInput source.Input, format sbom.Format, predica return } - s, err := generateSBOM(src, errs) + s, err := generateSBOM(src, cfg, errs) if err != nil { errs <- err return diff --git a/cmd/cmd.go b/cmd/cmd.go index f60b017d6..b9d3be239 100644 --- a/cmd/cmd.go +++ b/cmd/cmd.go @@ -14,6 +14,7 @@ import ( "github.com/anchore/syft/internal/logger" "github.com/anchore/syft/internal/version" "github.com/anchore/syft/syft" + "github.com/gookit/color" "github.com/spf13/cobra" "github.com/spf13/viper" @@ -113,12 +114,16 @@ func initAppConfig() { } func initLogging() { + initLoggingConfig(appConfig) +} + +func initLoggingConfig(appCfg *config.Application) { cfg := logger.LogrusConfig{ - EnableConsole: (appConfig.Log.FileLocation == "" || appConfig.CliOptions.Verbosity > 0) && !appConfig.Quiet, - EnableFile: appConfig.Log.FileLocation != "", - Level: appConfig.Log.LevelOpt, - Structured: appConfig.Log.Structured, - FileLocation: appConfig.Log.FileLocation, + EnableConsole: (appCfg.Log.FileLocation == "" || appCfg.CliOptions.Verbosity > 0) && !appCfg.Quiet, + EnableFile: appCfg.Log.FileLocation != "", + Level: appCfg.Log.LevelOpt, + Structured: appCfg.Log.Structured, + FileLocation: appCfg.Log.FileLocation, } logWrapper := logger.NewLogrusLogger(cfg) diff --git a/cmd/lib.go b/cmd/lib.go new file mode 100644 index 000000000..bc9022dbb --- /dev/null +++ b/cmd/lib.go @@ -0,0 +1,106 @@ +package cmd + +import ( + "fmt" + "os" + + "github.com/anchore/stereoscope" + "github.com/anchore/syft/internal/config" + "github.com/anchore/syft/internal/log" + "github.com/anchore/syft/internal/ui" + "github.com/anchore/syft/syft" + "github.com/anchore/syft/syft/logger" + syftLogger "github.com/anchore/syft/syft/logger" + "github.com/anchore/syft/syft/sbom" + "github.com/anchore/syft/syft/source" + "github.com/wagoodman/go-partybus" +) + +func libInitBase(cfg *config.Application, l logger.Logger, enable_ui bool) ([]ui.UI, error) { + if err := cfg.LibParseConfigValues(); err != nil { + return nil, fmt.Errorf("invalid application config: %w", err) + } + + var uis []ui.UI + uis = append(uis, ui.NewlibUI()) + if l == nil { + initLoggingConfig(cfg) + uis = ui.Select(isVerbose(cfg), cfg.Quiet) + } else { + libInitLoggingConfig(l) + uis = append(uis, ui.NewLoggerUI()) + } + + if enable_ui { + uis = ui.Select(isVerbose(cfg), cfg.Quiet) + } + + return uis, nil +} + +func libInitLoggingConfig(logWrapper syftLogger.Logger) { + syft.SetLogger(logWrapper) + stereoscope.SetLogger(logWrapper) +} + +func libInitEventBus() { + if eventSubscription == nil { + initEventBus() + } +} + +// LibPackagesExec run packages command as a library +// userInput: target +// cfg: syft configuration structure +// l: logger to attach to, nil for default syft logger +// enable_ui: enable disable ui output +// Function return sbom or errors. +func LibPackagesExec(userInput string, cfg *config.Application, l logger.Logger, enable_ui bool) (*sbom.SBOM, error) { + writer, err := makeWriter(cfg.Outputs, cfg.File) + if err != nil { + return nil, err + } + + uis, err := libInitBase(cfg, l, enable_ui) + if err != nil { + return nil, err + } + + defer func() { + if err := writer.Close(); err != nil { + log.Warnf("unable to write to report destination: %w", err) + } + }() + + // could be an image or a directory, with or without a scheme + si, err := source.ParseInput(userInput, cfg.Platform, true) + if err != nil { + return nil, fmt.Errorf("could not generate source input for packages command: %w", err) + } + + libInitEventBus() + outSbom, errs := packagesExecWorker(*si, cfg, writer) + return sbomEventLoop( + outSbom, errs, + setupSignals(), + eventSubscription, + stereoscope.Cleanup, + uis..., + ) +} + +func sbomEventLoop(outSbom <-chan *sbom.SBOM, workerErrs <-chan error, signals <-chan os.Signal, subscription *partybus.Subscription, cleanupFn func(), uxs ...ui.UI) (*sbom.SBOM, error) { + err := eventLoop(workerErrs, + signals, + subscription, + cleanupFn, + uxs...) + + var out *sbom.SBOM + if err == nil { + out = <-outSbom + } + + return out, err + +} diff --git a/cmd/packages.go b/cmd/packages.go index bb90a94fd..23f16c61f 100644 --- a/cmd/packages.go +++ b/cmd/packages.go @@ -10,6 +10,7 @@ import ( "github.com/anchore/syft/internal" "github.com/anchore/syft/internal/anchore" "github.com/anchore/syft/internal/bus" + "github.com/anchore/syft/internal/config" "github.com/anchore/syft/internal/formats/table" "github.com/anchore/syft/internal/log" "github.com/anchore/syft/internal/ui" @@ -82,7 +83,7 @@ var ( defer profile.Start(profile.MemProfile).Stop() } - return packagesExec(cmd, args) + return packagesExec(cmd, args, appConfig) }, ValidArgsFunction: dockerImageValidArgsFunction, } @@ -221,8 +222,8 @@ func validateInputArgs(cmd *cobra.Command, args []string) error { return cobra.MaximumNArgs(1)(cmd, args) } -func packagesExec(_ *cobra.Command, args []string) error { - writer, err := makeWriter(appConfig.Outputs, appConfig.File) +func packagesExec(_ *cobra.Command, args []string, cfg *config.Application) error { + writer, err := makeWriter(cfg.Outputs, cfg.File) if err != nil { return err } @@ -235,21 +236,23 @@ func packagesExec(_ *cobra.Command, args []string) error { // could be an image or a directory, with or without a scheme userInput := args[0] - si, err := source.ParseInput(userInput, appConfig.Platform, true) + si, err := source.ParseInput(userInput, cfg.Platform, true) if err != nil { return fmt.Errorf("could not generate source input for packages command: %w", err) } + _, errs := packagesExecWorker(*si, cfg, writer) + return eventLoop( - packagesExecWorker(*si, writer), + errs, setupSignals(), eventSubscription, stereoscope.Cleanup, - ui.Select(isVerbose(), appConfig.Quiet)..., + ui.Select(isVerbose(cfg), cfg.Quiet)..., ) } -func isVerbose() (result bool) { +func isVerbose(cfg *config.Application) (result bool) { isPipedInput, err := internal.IsPipedInput() if err != nil { // since we can't tell if there was piped input we assume that there could be to disable the ETUI @@ -257,11 +260,11 @@ func isVerbose() (result bool) { return true } // verbosity should consider if there is piped input (in which case we should not show the ETUI) - return appConfig.CliOptions.Verbosity > 0 || isPipedInput + return cfg.CliOptions.Verbosity > 0 || isPipedInput } -func generateSBOM(src *source.Source, errs chan error) (*sbom.SBOM, error) { - tasks, err := tasks() +func generateSBOM(src *source.Source, cfg *config.Application, errs chan error) (*sbom.SBOM, error) { + tasks, err := tasks(cfg) if err != nil { return nil, err } @@ -271,7 +274,7 @@ func generateSBOM(src *source.Source, errs chan error) (*sbom.SBOM, error) { Descriptor: sbom.Descriptor{ Name: internal.ApplicationName, Version: version.FromBuild().Version, - Configuration: appConfig, + Configuration: cfg, }, } @@ -291,12 +294,14 @@ func buildRelationships(s *sbom.SBOM, src *source.Source, tasks []task, errs cha s.Relationships = append(s.Relationships, mergeRelationships(relationships...)...) } -func packagesExecWorker(si source.Input, writer sbom.Writer) <-chan error { +func packagesExecWorker(si source.Input, cfg *config.Application, writer sbom.Writer) (chan *sbom.SBOM, <-chan error) { errs := make(chan error) + outSbom := make(chan *sbom.SBOM, 1) + go func() { defer close(errs) - src, cleanup, err := source.New(si, appConfig.Registry.ToOptions(), appConfig.Exclusions) + src, cleanup, err := source.New(si, cfg.Registry.ToOptions(), cfg.Exclusions) if cleanup != nil { defer cleanup() } @@ -305,7 +310,7 @@ func packagesExecWorker(si source.Input, writer sbom.Writer) <-chan error { return } - s, err := generateSBOM(src, errs) + s, err := generateSBOM(src, cfg, errs) if err != nil { errs <- err return @@ -315,8 +320,8 @@ func packagesExecWorker(si source.Input, writer sbom.Writer) <-chan error { errs <- fmt.Errorf("no SBOM produced for %q", si.UserInput) } - if appConfig.Anchore.Host != "" { - if err := runPackageSbomUpload(src, *s); err != nil { + if cfg.Anchore.Host != "" { + if err := runPackageSbomUpload(src, cfg, *s); err != nil { errs <- err return } @@ -326,8 +331,13 @@ func packagesExecWorker(si source.Input, writer sbom.Writer) <-chan error { Type: event.Exit, Value: func() error { return writer.Write(*s) }, }) + + if s != nil { + outSbom <- s + } }() - return errs + + return outSbom, errs } func mergeRelationships(cs ...<-chan artifact.Relationship) (relationships []artifact.Relationship) { @@ -340,34 +350,34 @@ func mergeRelationships(cs ...<-chan artifact.Relationship) (relationships []art return relationships } -func runPackageSbomUpload(src *source.Source, s sbom.SBOM) error { - log.Infof("uploading results to %s", appConfig.Anchore.Host) +func runPackageSbomUpload(src *source.Source, cfg *config.Application, s sbom.SBOM) error { + log.Infof("uploading results to %s", cfg.Anchore.Host) if src.Metadata.Scheme != source.ImageScheme { return fmt.Errorf("unable to upload results: only images are supported") } var dockerfileContents []byte - if appConfig.Anchore.Dockerfile != "" { - if _, err := os.Stat(appConfig.Anchore.Dockerfile); os.IsNotExist(err) { - return fmt.Errorf("unable dockerfile=%q does not exist: %w", appConfig.Anchore.Dockerfile, err) + if cfg.Anchore.Dockerfile != "" { + if _, err := os.Stat(cfg.Anchore.Dockerfile); os.IsNotExist(err) { + return fmt.Errorf("unable dockerfile=%q does not exist: %w", cfg.Anchore.Dockerfile, err) } - fh, err := os.Open(appConfig.Anchore.Dockerfile) + fh, err := os.Open(cfg.Anchore.Dockerfile) if err != nil { - return fmt.Errorf("unable to open dockerfile=%q: %w", appConfig.Anchore.Dockerfile, err) + return fmt.Errorf("unable to open dockerfile=%q: %w", cfg.Anchore.Dockerfile, err) } dockerfileContents, err = ioutil.ReadAll(fh) if err != nil { - return fmt.Errorf("unable to read dockerfile=%q: %w", appConfig.Anchore.Dockerfile, err) + return fmt.Errorf("unable to read dockerfile=%q: %w", cfg.Anchore.Dockerfile, err) } } c, err := anchore.NewClient(anchore.Configuration{ - BaseURL: appConfig.Anchore.Host, - Username: appConfig.Anchore.Username, - Password: appConfig.Anchore.Password, + BaseURL: cfg.Anchore.Host, + Username: cfg.Anchore.Username, + Password: cfg.Anchore.Password, }) if err != nil { return fmt.Errorf("failed to create anchore client: %w", err) @@ -377,12 +387,12 @@ func runPackageSbomUpload(src *source.Source, s sbom.SBOM) error { ImageMetadata: src.Image.Metadata, SBOM: s, Dockerfile: dockerfileContents, - OverwriteExistingUpload: appConfig.Anchore.OverwriteExistingImage, - Timeout: appConfig.Anchore.ImportTimeout, + OverwriteExistingUpload: cfg.Anchore.OverwriteExistingImage, + Timeout: cfg.Anchore.ImportTimeout, } if err := c.Import(context.Background(), importCfg); err != nil { - return fmt.Errorf("failed to upload results to host=%s: %+v", appConfig.Anchore.Host, err) + return fmt.Errorf("failed to upload results to host=%s: %+v", cfg.Anchore.Host, err) } return nil diff --git a/cmd/power_user.go b/cmd/power_user.go index 495328b97..43e6ffd1c 100644 --- a/cmd/power_user.go +++ b/cmd/power_user.go @@ -7,6 +7,7 @@ import ( "github.com/anchore/stereoscope" "github.com/anchore/syft/internal" "github.com/anchore/syft/internal/bus" + "github.com/anchore/syft/internal/config" "github.com/anchore/syft/internal/formats/syftjson" "github.com/anchore/syft/internal/log" "github.com/anchore/syft/internal/ui" @@ -94,14 +95,14 @@ func powerUserExec(_ *cobra.Command, args []string) error { }() return eventLoop( - powerUserExecWorker(userInput, writer), + powerUserExecWorker(userInput, appConfig, writer), setupSignals(), eventSubscription, stereoscope.Cleanup, - ui.Select(isVerbose(), appConfig.Quiet)..., + ui.Select(isVerbose(appConfig), appConfig.Quiet)..., ) } -func powerUserExecWorker(userInput string, writer sbom.Writer) <-chan error { +func powerUserExecWorker(userInput string, cfg *config.Application, writer sbom.Writer) <-chan error { errs := make(chan error) go func() { defer close(errs) @@ -110,7 +111,7 @@ func powerUserExecWorker(userInput string, writer sbom.Writer) <-chan error { appConfig.FileMetadata.Cataloger.Enabled = true appConfig.FileContents.Cataloger.Enabled = true appConfig.FileClassification.Cataloger.Enabled = true - tasks, err := tasks() + tasks, err := tasks(cfg) if err != nil { errs <- err return diff --git a/cmd/tasks.go b/cmd/tasks.go index 2d272e7db..d7e8e6560 100644 --- a/cmd/tasks.go +++ b/cmd/tasks.go @@ -4,6 +4,7 @@ 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" @@ -13,10 +14,10 @@ import ( type task func(*sbom.Artifacts, *source.Source) ([]artifact.Relationship, error) -func tasks() ([]task, error) { +func tasks(cfg *config.Application) ([]task, error) { var tasks []task - generators := []func() (task, error){ + generators := []func(cfg *config.Application) (task, error){ generateCatalogPackagesTask, generateCatalogFileMetadataTask, generateCatalogFileDigestsTask, @@ -26,7 +27,7 @@ func tasks() ([]task, error) { } for _, generator := range generators { - task, err := generator() + task, err := generator(cfg) if err != nil { return nil, err } @@ -39,13 +40,13 @@ func tasks() ([]task, error) { return tasks, nil } -func generateCatalogPackagesTask() (task, error) { - if !appConfig.Package.Cataloger.Enabled { +func generateCatalogPackagesTask(cfg *config.Application) (task, error) { + if !cfg.Package.Cataloger.Enabled { return nil, nil } task := func(results *sbom.Artifacts, src *source.Source) ([]artifact.Relationship, error) { - packageCatalog, relationships, theDistro, err := syft.CatalogPackages(src, appConfig.Package.ToConfig()) + packageCatalog, relationships, theDistro, err := syft.CatalogPackages(src, cfg.Package.ToConfig()) if err != nil { return nil, err } @@ -59,15 +60,15 @@ func generateCatalogPackagesTask() (task, error) { return task, nil } -func generateCatalogFileMetadataTask() (task, error) { - if !appConfig.FileMetadata.Cataloger.Enabled { +func generateCatalogFileMetadataTask(cfg *config.Application) (task, error) { + if !cfg.FileMetadata.Cataloger.Enabled { return nil, nil } metadataCataloger := file.NewMetadataCataloger() task := func(results *sbom.Artifacts, src *source.Source) ([]artifact.Relationship, error) { - resolver, err := src.FileResolver(appConfig.FileMetadata.Cataloger.ScopeOpt) + resolver, err := src.FileResolver(cfg.FileMetadata.Cataloger.ScopeOpt) if err != nil { return nil, err } @@ -83,8 +84,8 @@ func generateCatalogFileMetadataTask() (task, error) { return task, nil } -func generateCatalogFileDigestsTask() (task, error) { - if !appConfig.FileMetadata.Cataloger.Enabled { +func generateCatalogFileDigestsTask(cfg *config.Application) (task, error) { + if !cfg.FileMetadata.Cataloger.Enabled { return nil, nil } @@ -98,7 +99,7 @@ func generateCatalogFileDigestsTask() (task, error) { } var hashes []crypto.Hash - for _, hashStr := range appConfig.FileMetadata.Digests { + for _, hashStr := range cfg.FileMetadata.Digests { name := file.CleanDigestAlgorithmName(hashStr) hashObj, ok := supportedHashAlgorithms[name] if !ok { @@ -113,7 +114,7 @@ func generateCatalogFileDigestsTask() (task, error) { } task := func(results *sbom.Artifacts, src *source.Source) ([]artifact.Relationship, error) { - resolver, err := src.FileResolver(appConfig.FileMetadata.Cataloger.ScopeOpt) + resolver, err := src.FileResolver(cfg.FileMetadata.Cataloger.ScopeOpt) if err != nil { return nil, err } @@ -129,23 +130,23 @@ func generateCatalogFileDigestsTask() (task, error) { return task, nil } -func generateCatalogSecretsTask() (task, error) { - if !appConfig.Secrets.Cataloger.Enabled { +func generateCatalogSecretsTask(cfg *config.Application) (task, error) { + if !cfg.Secrets.Cataloger.Enabled { return nil, nil } - patterns, err := file.GenerateSearchPatterns(file.DefaultSecretsPatterns, appConfig.Secrets.AdditionalPatterns, appConfig.Secrets.ExcludePatternNames) + patterns, err := file.GenerateSearchPatterns(file.DefaultSecretsPatterns, cfg.Secrets.AdditionalPatterns, cfg.Secrets.ExcludePatternNames) if err != nil { return nil, err } - secretsCataloger, err := file.NewSecretsCataloger(patterns, appConfig.Secrets.RevealValues, appConfig.Secrets.SkipFilesAboveSize) + secretsCataloger, err := file.NewSecretsCataloger(patterns, cfg.Secrets.RevealValues, cfg.Secrets.SkipFilesAboveSize) if err != nil { return nil, err } task := func(results *sbom.Artifacts, src *source.Source) ([]artifact.Relationship, error) { - resolver, err := src.FileResolver(appConfig.Secrets.Cataloger.ScopeOpt) + resolver, err := src.FileResolver(cfg.Secrets.Cataloger.ScopeOpt) if err != nil { return nil, err } @@ -161,8 +162,8 @@ func generateCatalogSecretsTask() (task, error) { return task, nil } -func generateCatalogFileClassificationsTask() (task, error) { - if !appConfig.FileClassification.Cataloger.Enabled { +func generateCatalogFileClassificationsTask(cfg *config.Application) (task, error) { + if !cfg.FileClassification.Cataloger.Enabled { return nil, nil } @@ -173,7 +174,7 @@ func generateCatalogFileClassificationsTask() (task, error) { } task := func(results *sbom.Artifacts, src *source.Source) ([]artifact.Relationship, error) { - resolver, err := src.FileResolver(appConfig.FileClassification.Cataloger.ScopeOpt) + resolver, err := src.FileResolver(cfg.FileClassification.Cataloger.ScopeOpt) if err != nil { return nil, err } @@ -189,18 +190,18 @@ func generateCatalogFileClassificationsTask() (task, error) { return task, nil } -func generateCatalogContentsTask() (task, error) { - if !appConfig.FileContents.Cataloger.Enabled { +func generateCatalogContentsTask(cfg *config.Application) (task, error) { + if !cfg.FileContents.Cataloger.Enabled { return nil, nil } - contentsCataloger, err := file.NewContentsCataloger(appConfig.FileContents.Globs, appConfig.FileContents.SkipFilesAboveSize) + contentsCataloger, err := file.NewContentsCataloger(cfg.FileContents.Globs, cfg.FileContents.SkipFilesAboveSize) if err != nil { return nil, err } task := func(results *sbom.Artifacts, src *source.Source) ([]artifact.Relationship, error) { - resolver, err := src.FileResolver(appConfig.FileContents.Cataloger.ScopeOpt) + resolver, err := src.FileResolver(cfg.FileContents.Cataloger.ScopeOpt) if err != nil { return nil, err } diff --git a/internal/config/application.go b/internal/config/application.go index c9085fe95..db87c5b6e 100644 --- a/internal/config/application.go +++ b/internal/config/application.go @@ -49,6 +49,19 @@ type Application struct { Platform string `yaml:"platform" json:"platform" mapstructure:"platform"` } +type Anchore = anchore +type Pkg = pkg +type FileClassification = fileClassification +type FileContents = fileContents +type Secrets = secrets +type Registry = registry +type Attest = attest +type CatalogerOptions = catalogerOptions + +func (cfg *Application) LibParseConfigValues() error { + return cfg.parseConfigValues() +} + // PowerUserCatalogerEnabledDefault switches all catalogers to be enabled when running power-user command func PowerUserCatalogerEnabledDefault() { catalogerEnabledDefault = true diff --git a/internal/ui/lib_ui.go b/internal/ui/lib_ui.go new file mode 100644 index 000000000..5bc1be540 --- /dev/null +++ b/internal/ui/lib_ui.go @@ -0,0 +1,34 @@ +package ui + +import ( + syftEvent "github.com/anchore/syft/syft/event" + "github.com/wagoodman/go-partybus" +) + +func NewlibUI() UI { + return &libUI{} +} + +type libUI struct { + unsubscribe func() error +} + +func (h *libUI) Setup(unsubscribe func() error) error { + h.unsubscribe = unsubscribe + return nil +} + +func (h *libUI) Handle(event partybus.Event) error { + // ctx := context.Background() + switch { + case event.Type == syftEvent.Exit: + // this is the last expected event, stop listening to events + return h.unsubscribe() + default: + return nil + } +} + +func (h *libUI) Teardown(force bool) error { + return nil +} diff --git a/syft/lib.go b/syft/lib.go index a712e510a..6ad07b3a5 100644 --- a/syft/lib.go +++ b/syft/lib.go @@ -20,17 +20,32 @@ import ( "fmt" "github.com/anchore/syft/syft/artifact" + "github.com/anchore/syft/syft/pkg" "github.com/anchore/syft/internal/bus" + "github.com/anchore/syft/internal/config" "github.com/anchore/syft/internal/log" + "github.com/anchore/syft/syft/linux" "github.com/anchore/syft/syft/logger" - "github.com/anchore/syft/syft/pkg" "github.com/anchore/syft/syft/pkg/cataloger" "github.com/anchore/syft/syft/source" "github.com/wagoodman/go-partybus" ) +type Application = config.Application +type Anchore = config.Anchore +type CliOnlyOptions = config.CliOnlyOptions +type Pkg = config.Pkg +type FileMetadata = config.FileMetadata +type FileClassification = config.FileClassification +type FileContents = config.FileContents +type Secrets = config.Secrets +type Registry = config.Registry +type Attest = config.Attest +type CatalogerOptions = config.CatalogerOptions +type RegistryCredentials = config.RegistryCredentials + // CatalogPackages takes an inventory of packages from the given image from a particular perspective // (e.g. squashed source, all-layers source). Returns the discovered set of packages, the identified Linux // distribution, and the source object used to wrap the data source.