github.com/noqcks/syft@v0.0.0-20230920222752-a9e2c4e288e5/cmd/syft/cli/commands/poweruser.go (about) 1 package commands 2 3 import ( 4 "fmt" 5 "os" 6 7 "github.com/gookit/color" 8 "github.com/hashicorp/go-multierror" 9 "github.com/spf13/cobra" 10 11 "github.com/anchore/clio" 12 "github.com/anchore/stereoscope/pkg/image" 13 "github.com/anchore/syft/cmd/syft/cli/eventloop" 14 "github.com/anchore/syft/cmd/syft/cli/options" 15 "github.com/anchore/syft/internal" 16 "github.com/anchore/syft/syft/artifact" 17 "github.com/anchore/syft/syft/formats/syftjson" 18 "github.com/anchore/syft/syft/sbom" 19 "github.com/anchore/syft/syft/source" 20 ) 21 22 const powerUserExample = ` {{.appName}} {{.command}} <image> 23 DEPRECATED - THIS COMMAND WILL BE REMOVED in v1.0.0 24 Template outputs are not supported. 25 All behavior is controlled via application configuration and environment variables (see https://github.com/anchore/syft#configuration) 26 ` 27 28 type powerUserOptions struct { 29 options.Config `yaml:",inline" mapstructure:",squash"` 30 options.OutputFile `yaml:",inline" mapstructure:",squash"` 31 options.UpdateCheck `yaml:",inline" mapstructure:",squash"` 32 options.Catalog `yaml:",inline" mapstructure:",squash"` 33 } 34 35 func PowerUser(app clio.Application) *cobra.Command { 36 id := app.ID() 37 38 pkgs := options.DefaultCatalog() 39 pkgs.Secrets.Cataloger.Enabled = true 40 pkgs.FileMetadata.Cataloger.Enabled = true 41 pkgs.FileContents.Cataloger.Enabled = true 42 pkgs.FileClassification.Cataloger.Enabled = true 43 opts := &powerUserOptions{ 44 Catalog: pkgs, 45 } 46 47 return app.SetupCommand(&cobra.Command{ 48 Use: "power-user [IMAGE]", 49 Short: "Run bulk operations on container images", 50 Example: internal.Tprintf(powerUserExample, map[string]interface{}{ 51 "appName": id.Name, 52 "command": "power-user", 53 }), 54 Args: validatePackagesArgs, 55 Hidden: true, 56 PreRunE: applicationUpdateCheck(id, &opts.UpdateCheck), 57 RunE: func(cmd *cobra.Command, args []string) error { 58 return runPowerUser(id, opts, args[0]) 59 }, 60 }, opts) 61 } 62 63 //nolint:funlen 64 func runPowerUser(id clio.Identification, opts *powerUserOptions, userInput string) error { 65 writer, err := opts.SBOMWriter(syftjson.Format()) 66 if err != nil { 67 return err 68 } 69 defer func() { 70 // inform user at end of run that command will be removed 71 deprecated := color.Style{color.Red, color.OpBold}.Sprint("DEPRECATED: This command will be removed in v1.0.0") 72 fmt.Fprintln(os.Stderr, deprecated) 73 }() 74 75 tasks, err := eventloop.Tasks(&opts.Catalog) 76 if err != nil { 77 return err 78 } 79 80 detection, err := source.Detect( 81 userInput, 82 source.DetectConfig{ 83 DefaultImageSource: opts.DefaultImagePullSource, 84 }, 85 ) 86 if err != nil { 87 return fmt.Errorf("could not deteremine source: %w", err) 88 } 89 90 var platform *image.Platform 91 92 if opts.Platform != "" { 93 platform, err = image.NewPlatform(opts.Platform) 94 if err != nil { 95 return fmt.Errorf("invalid platform: %w", err) 96 } 97 } 98 99 src, err := detection.NewSource( 100 source.DetectionSourceConfig{ 101 Alias: source.Alias{ 102 Name: opts.Source.Name, 103 Version: opts.Source.Version, 104 }, 105 RegistryOptions: opts.Registry.ToOptions(), 106 Platform: platform, 107 Exclude: source.ExcludeConfig{ 108 Paths: opts.Exclusions, 109 }, 110 DigestAlgorithms: nil, 111 BasePath: opts.BasePath, 112 }, 113 ) 114 115 if src != nil { 116 defer src.Close() 117 } 118 if err != nil { 119 return fmt.Errorf("failed to construct source from user input %q: %w", userInput, err) 120 } 121 122 s := sbom.SBOM{ 123 Source: src.Describe(), 124 Descriptor: sbom.Descriptor{ 125 Name: id.Name, 126 Version: id.Version, 127 Configuration: opts, 128 }, 129 } 130 131 var errs error 132 var relationships []<-chan artifact.Relationship 133 for _, task := range tasks { 134 c := make(chan artifact.Relationship) 135 relationships = append(relationships, c) 136 137 go func(task eventloop.Task) { 138 err := eventloop.RunTask(task, &s.Artifacts, src, c) 139 errs = multierror.Append(errs, err) 140 }(task) 141 } 142 143 if errs != nil { 144 return errs 145 } 146 147 s.Relationships = append(s.Relationships, mergeRelationships(relationships...)...) 148 149 if err := writer.Write(s); err != nil { 150 return fmt.Errorf("failed to write sbom: %w", err) 151 } 152 153 return nil 154 }