github.com/anchore/syft@v1.4.2-0.20240516191711-1bec1fc5d397/examples/create_custom_sbom/main.go (about) 1 package main 2 3 import ( 4 "context" 5 "crypto" 6 "fmt" 7 "os" 8 9 "gopkg.in/yaml.v3" 10 11 "github.com/anchore/syft/syft" 12 "github.com/anchore/syft/syft/cataloging" 13 "github.com/anchore/syft/syft/cataloging/filecataloging" 14 "github.com/anchore/syft/syft/cataloging/pkgcataloging" 15 "github.com/anchore/syft/syft/file" 16 "github.com/anchore/syft/syft/sbom" 17 "github.com/anchore/syft/syft/source" 18 ) 19 20 const defaultImage = "alpine:3.19" 21 22 func main() { 23 // automagically get a source.Source for arbitrary string input 24 src := getSource(imageReference()) 25 26 // will catalog the given source and return a SBOM keeping in mind several configurable options 27 sbom := getSBOM(src) 28 29 // show a simple package summary 30 summarize(sbom) 31 32 // show the alpine-configuration cataloger results 33 showAlpineConfiguration(sbom) 34 } 35 36 func imageReference() string { 37 // read an image string reference from the command line or use a default 38 if len(os.Args) > 1 { 39 return os.Args[1] 40 } 41 return defaultImage 42 } 43 44 func getSource(input string) source.Source { 45 fmt.Println("detecting source type for input:", input, "...") 46 47 src, err := syft.GetSource(context.Background(), input, nil) 48 49 if err != nil { 50 panic(err) 51 } 52 53 return src 54 } 55 56 func getSBOM(src source.Source) sbom.SBOM { 57 fmt.Println("creating SBOM...") 58 59 cfg := syft.DefaultCreateSBOMConfig(). 60 // run the catalogers in parallel (5 at a time concurrently max) 61 WithParallelism(5). 62 // bake a specific tool name and version into the SBOM 63 WithTool("my-tool", "v1.0"). 64 // catalog all files with 3 digests 65 WithFilesConfig( 66 filecataloging.DefaultConfig(). 67 WithSelection(file.AllFilesSelection). 68 WithHashers( 69 crypto.MD5, 70 crypto.SHA1, 71 crypto.SHA256, 72 ), 73 ). 74 // only use OS related catalogers that would have been used with the kind of 75 // source type (container image or directory), but also add a specific python cataloger 76 WithCatalogerSelection( 77 pkgcataloging.NewSelectionRequest(). 78 WithSubSelections("os"). 79 WithAdditions("python-package-cataloger"), 80 ). 81 // which relationships to include 82 WithRelationshipsConfig( 83 cataloging.RelationshipsConfig{ 84 PackageFileOwnership: true, 85 PackageFileOwnershipOverlap: true, 86 ExcludeBinaryPackagesWithFileOwnershipOverlap: true, 87 }, 88 ). 89 // add your own cataloger to the mix 90 WithCatalogers( 91 pkgcataloging.NewAlwaysEnabledCatalogerReference( 92 newAlpineConfigurationCataloger(), 93 ), 94 ) 95 96 s, err := syft.CreateSBOM(context.Background(), src, cfg) 97 if err != nil { 98 panic(err) 99 } 100 101 return *s 102 } 103 104 func summarize(s sbom.SBOM) { 105 fmt.Printf("Cataloged %d packages:\n", s.Artifacts.Packages.PackageCount()) 106 for _, p := range s.Artifacts.Packages.Sorted() { 107 fmt.Printf(" - %s@%s (%s)\n", p.Name, p.Version, p.Type) 108 } 109 fmt.Println() 110 } 111 112 func showAlpineConfiguration(s sbom.SBOM) { 113 pkgs := s.Artifacts.Packages.PackagesByName("alpine-configuration") 114 if len(pkgs) == 0 { 115 fmt.Println("no alpine-configuration package found") 116 return 117 } 118 119 p := pkgs[0] 120 121 fmt.Printf("All 'alpine-configuration' packages: %s\n", p.Version) 122 meta, err := yaml.Marshal(p.Metadata) 123 if err != nil { 124 panic(err) 125 } 126 fmt.Println(string(meta)) 127 128 }