Skip to content

Commit

Permalink
promote catalog task pattern to all commands (#636)
Browse files Browse the repository at this point in the history
Signed-off-by: Christopher Angelo Phillips <christopher.phillips@anchore.com>
  • Loading branch information
spiffcs committed Nov 19, 2021
1 parent d76c868 commit 4f00995
Show file tree
Hide file tree
Showing 10 changed files with 112 additions and 82 deletions.
10 changes: 8 additions & 2 deletions cmd/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,13 @@ func initCmdAliasBindings() {
panic(err)
}

if activeCmd == packagesCmd || activeCmd == rootCmd {
// enable all cataloger by default if power-user command is run
if activeCmd == powerUserCmd {
config.PowerUserCatalogerEnabledDefault()
}

switch activeCmd {
case packagesCmd, rootCmd:
// note: we need to lazily bind config options since they are shared between both the root command
// and the packages command. Otherwise there will be global viper state that is in contention.
// See for more details: https://github.com/spf13/viper/issues/233 . Additionally, the bindings must occur BEFORE
Expand All @@ -58,7 +64,7 @@ func initCmdAliasBindings() {
if err = bindPackagesConfigOptions(activeCmd.Flags()); err != nil {
panic(err)
}
} else {
default:
// even though the root command or packages command is NOT being run, we still need default bindings
// such that application config parsing passes.
if err = bindPackagesConfigOptions(packagesCmd.Flags()); err != nil {
Expand Down
57 changes: 43 additions & 14 deletions cmd/packages.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"
"io/ioutil"
"os"
"sync"

"github.com/anchore/stereoscope"
"github.com/anchore/syft/internal"
Expand All @@ -13,7 +14,7 @@ import (
"github.com/anchore/syft/internal/formats"
"github.com/anchore/syft/internal/log"
"github.com/anchore/syft/internal/ui"
"github.com/anchore/syft/syft"
"github.com/anchore/syft/syft/artifact"
"github.com/anchore/syft/syft/event"
"github.com/anchore/syft/syft/format"
"github.com/anchore/syft/syft/sbom"
Expand Down Expand Up @@ -238,6 +239,12 @@ func packagesExecWorker(userInput string) <-chan error {
go func() {
defer close(errs)

tasks, err := tasks()
if err != nil {
errs <- err
return
}

f := formats.ByOption(packagesPresenterOpt)
if f == nil {
errs <- fmt.Errorf("unknown format: %s", packagesPresenterOpt)
Expand All @@ -255,36 +262,58 @@ func packagesExecWorker(userInput string) <-chan error {
defer cleanup()
}

catalog, relationships, d, err := syft.CatalogPackages(src, appConfig.Package.Cataloger.ScopeOpt)
if err != nil {
errs <- fmt.Errorf("failed to catalog input: %w", err)
return
s := sbom.SBOM{
Source: src.Metadata,
}

var relationships []<-chan artifact.Relationship
for _, task := range tasks {
c := make(chan artifact.Relationship)
relationships = append(relationships, c)

go runTask(task, &s.Artifacts, src, c, errs)
}

sbomResult := sbom.SBOM{
Artifacts: sbom.Artifacts{
PackageCatalog: catalog,
Distro: d,
},
Relationships: relationships,
Source: src.Metadata,
for relationship := range mergeRelationships(relationships...) {
s.Relationships = append(s.Relationships, relationship)
}

if appConfig.Anchore.Host != "" {
if err := runPackageSbomUpload(src, sbomResult); err != nil {
if err := runPackageSbomUpload(src, s); err != nil {
errs <- err
return
}
}

bus.Publish(partybus.Event{
Type: event.PresenterReady,
Value: f.Presenter(sbomResult),
Value: f.Presenter(s),
})
}()
return errs
}

func mergeRelationships(cs ...<-chan artifact.Relationship) <-chan artifact.Relationship {
var wg sync.WaitGroup
var relationships = make(chan artifact.Relationship)

wg.Add(len(cs))
for _, c := range cs {
go func(c <-chan artifact.Relationship) {
for n := range c {
relationships <- n
}
wg.Done()
}(c)
}

go func() {
wg.Wait()
close(relationships)
}()
return relationships
}

func runPackageSbomUpload(src *source.Source, s sbom.SBOM) error {
log.Infof("uploading results to %s", appConfig.Anchore.Host)

Expand Down
57 changes: 17 additions & 40 deletions cmd/power_user.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ package cmd

import (
"fmt"
"sync"
"os"

"github.com/anchore/syft/syft/artifact"
"github.com/gookit/color"

"github.com/anchore/syft/syft/sbom"

Expand All @@ -23,6 +24,8 @@ import (

const powerUserExample = ` {{.appName}} {{.command}} <image>
DEPRECATED - THIS COMMAND WILL BE REMOVED in v1.0.0
Only image sources are supported (e.g. docker: , docker-archive: , oci: , etc.), the directory source (dir:) is not supported.
All behavior is controlled via application configuration and environment variables (see https://github.com/anchore/syft#configuration)
Expand Down Expand Up @@ -76,6 +79,10 @@ func powerUserExec(_ *cobra.Command, args []string) error {
if err := closer(); err != nil {
log.Warnf("unable to write to report destination: %+v", err)
}

// inform user at end of run that command will be removed
deprecated := color.Style{color.Red, color.OpBold}.Sprint("DEPRECATED: This command will be removed in v1.0.0")
fmt.Fprintln(os.Stderr, deprecated)
}()

if err != nil {
Expand All @@ -95,7 +102,11 @@ func powerUserExecWorker(userInput string) <-chan error {
go func() {
defer close(errs)

tasks, err := powerUserTasks()
appConfig.Secrets.Cataloger.Enabled = true
appConfig.FileMetadata.Cataloger.Enabled = true
appConfig.FileContents.Cataloger.Enabled = true
appConfig.FileClassification.Cataloger.Enabled = true
tasks, err := tasks()
if err != nil {
errs <- err
return
Expand All @@ -116,15 +127,15 @@ func powerUserExecWorker(userInput string) <-chan error {
Source: src.Metadata,
}

var results []<-chan artifact.Relationship
var relationships []<-chan artifact.Relationship
for _, task := range tasks {
c := make(chan artifact.Relationship)
results = append(results, c)
relationships = append(relationships, c)

go runTask(task, &s.Artifacts, src, c, errs)
}

for relationship := range mergeResults(results...) {
for relationship := range mergeRelationships(relationships...) {
s.Relationships = append(s.Relationships, relationship)
}

Expand All @@ -133,40 +144,6 @@ func powerUserExecWorker(userInput string) <-chan error {
Value: poweruser.NewJSONPresenter(s, *appConfig),
})
}()
return errs
}

func runTask(t powerUserTask, 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
}
}

func mergeResults(cs ...<-chan artifact.Relationship) <-chan artifact.Relationship {
var wg sync.WaitGroup
var results = make(chan artifact.Relationship)

wg.Add(len(cs))
for _, c := range cs {
go func(c <-chan artifact.Relationship) {
for n := range c {
results <- n
}
wg.Done()
}(c)
}

go func() {
wg.Wait()
close(results)
}()
return results
return errs
}
53 changes: 33 additions & 20 deletions cmd/power_user_tasks.go → cmd/tasks.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,34 +4,33 @@ import (
"crypto"
"fmt"

"github.com/anchore/syft/syft/artifact"

"github.com/anchore/syft/syft/sbom"

"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 powerUserTask func(*sbom.Artifacts, *source.Source) ([]artifact.Relationship, error)
type task func(*sbom.Artifacts, *source.Source) ([]artifact.Relationship, error)

func powerUserTasks() ([]powerUserTask, error) {
var tasks []powerUserTask
func tasks() ([]task, error) {
var tasks []task

generators := []func() (powerUserTask, error){
catalogPackagesTask,
catalogFileMetadataTask,
catalogFileDigestsTask,
catalogSecretsTask,
catalogFileClassificationsTask,
catalogContentsTask,
generators := []func() (task, error){
generateCatalogPackagesTask,
generateCatalogFileMetadataTask,
generateCatalogFileDigestsTask,
generateCatalogSecretsTask,
generateCatalogFileClassificationsTask,
generateCatalogContentsTask,
}

for _, generator := range generators {
task, err := generator()
if err != nil {
return nil, err
}

if task != nil {
tasks = append(tasks, task)
}
Expand All @@ -40,7 +39,7 @@ func powerUserTasks() ([]powerUserTask, error) {
return tasks, nil
}

func catalogPackagesTask() (powerUserTask, error) {
func generateCatalogPackagesTask() (task, error) {
if !appConfig.Package.Cataloger.Enabled {
return nil, nil
}
Expand All @@ -60,7 +59,7 @@ func catalogPackagesTask() (powerUserTask, error) {
return task, nil
}

func catalogFileMetadataTask() (powerUserTask, error) {
func generateCatalogFileMetadataTask() (task, error) {
if !appConfig.FileMetadata.Cataloger.Enabled {
return nil, nil
}
Expand All @@ -84,7 +83,7 @@ func catalogFileMetadataTask() (powerUserTask, error) {
return task, nil
}

func catalogFileDigestsTask() (powerUserTask, error) {
func generateCatalogFileDigestsTask() (task, error) {
if !appConfig.FileMetadata.Cataloger.Enabled {
return nil, nil
}
Expand Down Expand Up @@ -130,7 +129,7 @@ func catalogFileDigestsTask() (powerUserTask, error) {
return task, nil
}

func catalogSecretsTask() (powerUserTask, error) {
func generateCatalogSecretsTask() (task, error) {
if !appConfig.Secrets.Cataloger.Enabled {
return nil, nil
}
Expand Down Expand Up @@ -162,7 +161,7 @@ func catalogSecretsTask() (powerUserTask, error) {
return task, nil
}

func catalogFileClassificationsTask() (powerUserTask, error) {
func generateCatalogFileClassificationsTask() (task, error) {
if !appConfig.FileClassification.Cataloger.Enabled {
return nil, nil
}
Expand Down Expand Up @@ -190,7 +189,7 @@ func catalogFileClassificationsTask() (powerUserTask, error) {
return task, nil
}

func catalogContentsTask() (powerUserTask, error) {
func generateCatalogContentsTask() (task, error) {
if !appConfig.FileContents.Cataloger.Enabled {
return nil, nil
}
Expand All @@ -216,3 +215,17 @@ func catalogContentsTask() (powerUserTask, error) {

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
}
}
7 changes: 7 additions & 0 deletions internal/config/application.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import (

var ErrApplicationConfigNotFound = fmt.Errorf("application config not found")

var catalogerEnabledDefault = false

type defaultValueLoader interface {
loadDefaultValues(*viper.Viper)
}
Expand Down Expand Up @@ -44,6 +46,11 @@ type Application struct {
Registry registry `yaml:"registry" json:"registry" mapstructure:"registry"`
}

// PowerUserCatalogerEnabledDefault switches all catalogers to be enabled when running power-user command
func PowerUserCatalogerEnabledDefault() {
catalogerEnabledDefault = true
}

func newApplicationConfig(v *viper.Viper, cliOpts CliOnlyOptions) *Application {
config := &Application{
CliOptions: cliOpts,
Expand Down
2 changes: 1 addition & 1 deletion internal/config/file_classification.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ type fileClassification struct {
}

func (cfg fileClassification) loadDefaultValues(v *viper.Viper) {
v.SetDefault("file-classification.cataloger.enabled", true)
v.SetDefault("file-classification.cataloger.enabled", catalogerEnabledDefault)
v.SetDefault("file-classification.cataloger.scope", source.SquashedScope)
}

Expand Down
2 changes: 1 addition & 1 deletion internal/config/file_contents.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ type fileContents struct {
}

func (cfg fileContents) loadDefaultValues(v *viper.Viper) {
v.SetDefault("file-contents.cataloger.enabled", true)
v.SetDefault("file-contents.cataloger.enabled", catalogerEnabledDefault)
v.SetDefault("file-contents.cataloger.scope", source.SquashedScope)
v.SetDefault("file-contents.skip-files-above-size", 1*file.MB)
v.SetDefault("file-contents.globs", []string{})
Expand Down
2 changes: 1 addition & 1 deletion internal/config/file_metadata.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ type FileMetadata struct {
}

func (cfg FileMetadata) loadDefaultValues(v *viper.Viper) {
v.SetDefault("file-metadata.cataloger.enabled", true)
v.SetDefault("file-metadata.cataloger.enabled", catalogerEnabledDefault)
v.SetDefault("file-metadata.cataloger.scope", source.SquashedScope)
v.SetDefault("file-metadata.digests", []string{"sha256"})
}
Expand Down

0 comments on commit 4f00995

Please sign in to comment.