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  }