github.com/lineaje-labs/syft@v0.98.1-0.20231227153149-9e393f60ff1b/cmd/syft/cli/commands/convert.go (about) 1 package commands 2 3 import ( 4 "fmt" 5 "io" 6 "os" 7 8 "github.com/spf13/cobra" 9 10 "github.com/anchore/clio" 11 "github.com/anchore/syft/cmd/syft/cli/options" 12 "github.com/anchore/syft/syft/format" 13 "github.com/lineaje-labs/syft/cmd/syft/internal/ui" 14 "github.com/lineaje-labs/syft/internal" 15 "github.com/lineaje-labs/syft/internal/log" 16 ) 17 18 const ( 19 convertExample = ` {{.appName}} {{.command}} img.syft.json -o spdx-json convert a syft SBOM to spdx-json, output goes to stdout 20 {{.appName}} {{.command}} img.syft.json -o cyclonedx-json=img.cdx.json convert a syft SBOM to CycloneDX, output is written to the file "img.cdx.json"" 21 {{.appName}} {{.command}} - -o spdx-json convert an SBOM from STDIN to spdx-json 22 ` 23 ) 24 25 type ConvertOptions struct { 26 options.Config `yaml:",inline" mapstructure:",squash"` 27 options.Output `yaml:",inline" mapstructure:",squash"` 28 options.UpdateCheck `yaml:",inline" mapstructure:",squash"` 29 } 30 31 //nolint:dupl 32 func Convert(app clio.Application) *cobra.Command { 33 id := app.ID() 34 35 opts := &ConvertOptions{ 36 UpdateCheck: options.DefaultUpdateCheck(), 37 Output: options.DefaultOutput(), 38 } 39 40 return app.SetupCommand(&cobra.Command{ 41 Use: "convert [SOURCE-SBOM] -o [FORMAT]", 42 Short: "Convert between SBOM formats", 43 Long: "[Experimental] Convert SBOM files to, and from, SPDX, CycloneDX and Syft's format. For more info about data loss between formats see https://github.com/anchore/syft#format-conversion-experimental", 44 Example: internal.Tprintf(convertExample, map[string]interface{}{ 45 "appName": id.Name, 46 "command": "convert", 47 }), 48 Args: validateConvertArgs, 49 PreRunE: applicationUpdateCheck(id, &opts.UpdateCheck), 50 RunE: func(cmd *cobra.Command, args []string) error { 51 restoreStdout := ui.CaptureStdoutToTraceLog() 52 defer restoreStdout() 53 54 return RunConvert(opts, args[0]) 55 }, 56 }, opts) 57 } 58 59 func validateConvertArgs(cmd *cobra.Command, args []string) error { 60 return validateArgs(cmd, args, "an SBOM argument is required") 61 } 62 63 func RunConvert(opts *ConvertOptions, userInput string) error { 64 log.Warn("convert is an experimental feature, run `syft convert -h` for help") 65 66 writer, err := opts.SBOMWriter() 67 if err != nil { 68 return err 69 } 70 71 var reader io.ReadSeekCloser 72 73 if userInput == "-" { 74 // though os.Stdin is an os.File, it does not support seeking 75 // you will get errors such as "seek /dev/stdin: illegal seek". 76 // We need to buffer what we read. 77 reader = internal.NewBufferedSeeker(os.Stdin) 78 } else { 79 f, err := os.Open(userInput) 80 if err != nil { 81 return fmt.Errorf("failed to open SBOM file: %w", err) 82 } 83 defer func() { 84 _ = f.Close() 85 }() 86 reader = f 87 } 88 89 s, _, _, err := format.Decode(reader) 90 if err != nil { 91 return fmt.Errorf("failed to decode SBOM: %w", err) 92 } 93 94 if s == nil { 95 return fmt.Errorf("no SBOM produced") 96 } 97 98 if err := writer.Write(*s); err != nil { 99 return fmt.Errorf("failed to write SBOM: %w", err) 100 } 101 102 return nil 103 }