github.com/anchore/syft@v1.38.2/internal/task/unknowns_tasks.go (about) 1 package task 2 3 import ( 4 "context" 5 "strings" 6 7 intFile "github.com/anchore/syft/internal/file" 8 "github.com/anchore/syft/internal/log" 9 "github.com/anchore/syft/internal/sbomsync" 10 "github.com/anchore/syft/syft/cataloging" 11 "github.com/anchore/syft/syft/file" 12 "github.com/anchore/syft/syft/pkg" 13 "github.com/anchore/syft/syft/sbom" 14 ) 15 16 const unknownsLabelerTaskName = "unknowns-labeler" 17 18 func NewUnknownsLabelerTask(cfg cataloging.UnknownsConfig) Task { 19 return NewTask(unknownsLabelerTaskName, unknownsLabelerTask{cfg}.processUnknowns) 20 } 21 22 type unknownsLabelerTask struct { 23 cataloging.UnknownsConfig 24 } 25 26 // processUnknowns removes unknown entries that have valid packages reported for the locations 27 func (c unknownsLabelerTask) processUnknowns(_ context.Context, resolver file.Resolver, builder sbomsync.Builder) error { 28 accessor := builder.(sbomsync.Accessor) 29 accessor.WriteToSBOM(func(s *sbom.SBOM) { 30 c.finalize(resolver, s) 31 }) 32 return nil 33 } 34 35 func (c unknownsLabelerTask) finalize(resolver file.Resolver, s *sbom.SBOM) { 36 hasPackageReference := coordinateReferenceLookup(resolver, s) 37 38 if c.RemoveWhenPackagesDefined { 39 for coords := range s.Artifacts.Unknowns { 40 if !hasPackageReference(coords) { 41 continue 42 } 43 delete(s.Artifacts.Unknowns, coords) 44 } 45 } 46 47 if s.Artifacts.Unknowns == nil { 48 s.Artifacts.Unknowns = map[file.Coordinates][]string{} 49 } 50 51 if c.IncludeExecutablesWithoutPackages { 52 for coords := range s.Artifacts.Executables { 53 if !hasPackageReference(coords) { 54 s.Artifacts.Unknowns[coords] = append(s.Artifacts.Unknowns[coords], formatUnknown("no package identified in executable file", unknownsLabelerTaskName)) 55 } 56 } 57 } 58 59 if c.IncludeUnexpandedArchives { 60 ctx := context.Background() 61 for coords := range s.Artifacts.FileMetadata { 62 format, _, notArchiveErr := intFile.IdentifyArchive(ctx, coords.RealPath, nil) 63 if format != nil && notArchiveErr == nil && !hasPackageReference(coords) { 64 s.Artifacts.Unknowns[coords] = append(s.Artifacts.Unknowns[coords], "archive not cataloged") 65 } 66 } 67 } 68 } 69 70 func formatUnknown(err string, task ...string) string { 71 return strings.Join(task, "/") + ": " + err 72 } 73 74 func coordinateReferenceLookup(resolver file.Resolver, s *sbom.SBOM) func(coords file.Coordinates) bool { 75 allPackageCoords := file.NewCoordinateSet() 76 77 // include all directly included locations that result in packages 78 for p := range s.Artifacts.Packages.Enumerate() { 79 allPackageCoords.Add(p.Locations.CoordinateSet().ToSlice()...) 80 } 81 82 // include owned files, for example specified by package managers. 83 // relationships for these owned files may be disabled, but we always want to include them 84 for p := range s.Artifacts.Packages.Enumerate() { 85 if f, ok := p.Metadata.(pkg.FileOwner); ok { 86 for _, ownedFilePath := range f.OwnedFiles() { 87 // resolve these owned files, as they may have symlinks 88 // but coordinates we will test against are always absolute paths 89 locations, err := resolver.FilesByPath(ownedFilePath) 90 if err != nil { 91 log.Debugf("unable to resolve owned file '%s': %v", ownedFilePath, err) 92 } 93 for _, loc := range locations { 94 allPackageCoords.Add(loc.Coordinates) 95 } 96 } 97 } 98 } 99 100 // include relationships 101 for _, r := range s.Relationships { 102 _, fromPkgOk := r.From.(pkg.Package) 103 fromFile, fromFileOk := r.From.(file.Coordinates) 104 _, toPkgOk := r.To.(pkg.Package) 105 toFile, toFileOk := r.To.(file.Coordinates) 106 if fromPkgOk && toFileOk { 107 allPackageCoords.Add(toFile) 108 } else if fromFileOk && toPkgOk { 109 allPackageCoords.Add(fromFile) 110 } 111 } 112 113 return allPackageCoords.Contains 114 }