github.com/noqcks/syft@v0.0.0-20230920222752-a9e2c4e288e5/syft/pkg/cataloger/nix/cataloger.go (about) 1 package nix 2 3 import ( 4 "fmt" 5 6 "github.com/bmatcuk/doublestar/v4" 7 8 "github.com/anchore/syft/internal/log" 9 "github.com/anchore/syft/syft/artifact" 10 "github.com/anchore/syft/syft/file" 11 "github.com/anchore/syft/syft/pkg" 12 ) 13 14 const ( 15 catalogerName = "nix-store-cataloger" 16 nixStoreGlob = "**/nix/store/*" 17 ) 18 19 // StoreCataloger finds package outputs installed in the Nix store location (/nix/store/*). 20 type StoreCataloger struct{} 21 22 func NewStoreCataloger() *StoreCataloger { 23 return &StoreCataloger{} 24 } 25 26 func (c *StoreCataloger) Name() string { 27 return catalogerName 28 } 29 30 func (c *StoreCataloger) Catalog(resolver file.Resolver) ([]pkg.Package, []artifact.Relationship, error) { 31 // we want to search for only directories, which isn't possible via the stereoscope API, so we need to apply the glob manually on all returned paths 32 var pkgs []pkg.Package 33 var filesByPath = make(map[string]*file.LocationSet) 34 for location := range resolver.AllLocations() { 35 matchesStorePath, err := doublestar.Match(nixStoreGlob, location.RealPath) 36 if err != nil { 37 return nil, nil, fmt.Errorf("failed to match nix store path: %w", err) 38 } 39 40 parentStorePath := findParentNixStorePath(location.RealPath) 41 if parentStorePath != "" { 42 if _, ok := filesByPath[parentStorePath]; !ok { 43 s := file.NewLocationSet() 44 filesByPath[parentStorePath] = &s 45 } 46 filesByPath[parentStorePath].Add(location) 47 } 48 49 if !matchesStorePath { 50 continue 51 } 52 53 storePath := parseNixStorePath(location.RealPath) 54 55 if storePath == nil || !storePath.isValidPackage() { 56 continue 57 } 58 59 p := newNixStorePackage(*storePath, location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation)) 60 pkgs = append(pkgs, p) 61 } 62 63 // add file sets to packages 64 for i := range pkgs { 65 p := &pkgs[i] 66 locations := p.Locations.ToSlice() 67 if len(locations) == 0 { 68 log.WithFields("package", p.Name).Warn("nix package has no evidence locations associated") 69 continue 70 } 71 parentStorePath := locations[0].RealPath 72 files, ok := filesByPath[parentStorePath] 73 if !ok { 74 log.WithFields("path", parentStorePath, "nix-store-path", parentStorePath).Warn("found a nix store file for a non-existent package") 75 continue 76 } 77 appendFiles(p, files.ToSlice()...) 78 } 79 80 return pkgs, nil, nil 81 } 82 83 func appendFiles(p *pkg.Package, location ...file.Location) { 84 metadata, ok := p.Metadata.(pkg.NixStoreMetadata) 85 if !ok { 86 log.WithFields("package", p.Name).Warn("nix package metadata missing") 87 return 88 } 89 90 for _, l := range location { 91 metadata.Files = append(metadata.Files, l.RealPath) 92 } 93 94 if metadata.Files == nil { 95 // note: we always have an allocated collection for output 96 metadata.Files = []string{} 97 } 98 99 p.Metadata = metadata 100 p.SetID() 101 }