github.com/anchore/syft@v1.38.2/internal/relationship/exclude_binaries_by_file_ownership_overlap.go (about) 1 package relationship 2 3 import ( 4 "reflect" 5 "slices" 6 7 "github.com/anchore/syft/internal/sbomsync" 8 "github.com/anchore/syft/syft/artifact" 9 "github.com/anchore/syft/syft/pkg" 10 "github.com/anchore/syft/syft/sbom" 11 ) 12 13 var ( 14 osCatalogerTypes = []pkg.Type{ 15 pkg.AlpmPkg, 16 pkg.ApkPkg, 17 pkg.DebPkg, 18 pkg.NixPkg, 19 pkg.PortagePkg, 20 pkg.RpmPkg, 21 } 22 binaryCatalogerTypes = []pkg.Type{ 23 pkg.BinaryPkg, 24 } 25 bitnamiCatalogerTypes = []pkg.Type{ 26 pkg.BitnamiPkg, 27 } 28 binaryMetadataTypes = []string{ 29 reflect.TypeOf(pkg.ELFBinaryPackageNoteJSONPayload{}).Name(), 30 reflect.TypeOf(pkg.BinarySignature{}).Name(), 31 reflect.TypeOf(pkg.JavaVMInstallation{}).Name(), 32 } 33 ) 34 35 func ExcludeBinariesByFileOwnershipOverlap(accessor sbomsync.Accessor) { 36 accessor.WriteToSBOM(func(s *sbom.SBOM) { 37 for _, r := range s.Relationships { 38 if idToRemove := excludeByFileOwnershipOverlap(r, s.Artifacts.Packages); idToRemove != "" { 39 s.Artifacts.Packages.Delete(idToRemove) 40 s.Relationships = RemoveRelationshipsByID(s.Relationships, idToRemove) 41 } 42 } 43 }) 44 } 45 46 // excludeByFileOwnershipOverlap will remove packages that should be overridden by a more authoritative package, 47 // such as an OS package or a package from a cataloger with more specific information being raised up. 48 func excludeByFileOwnershipOverlap(r artifact.Relationship, c *pkg.Collection) artifact.ID { 49 if artifact.OwnershipByFileOverlapRelationship != r.Type { 50 return "" 51 } 52 53 parent := c.Package(r.From.ID()) 54 if parent == nil { 55 return "" 56 } 57 58 child := c.Package(r.To.ID()) 59 if child == nil { 60 return "" 61 } 62 63 if idToRemove := identifyOverlappingOSRelationship(parent, child); idToRemove != "" { 64 return idToRemove 65 } 66 67 if idToRemove := identifyOverlappingJVMRelationship(parent, child); idToRemove != "" { 68 return idToRemove 69 } 70 71 if idToRemove := identifyOverlappingBitnamiRelationship(parent, child); idToRemove != "" { 72 return idToRemove 73 } 74 75 return "" 76 } 77 78 // identifyOverlappingJVMRelationship indicates the package to remove if this is a binary -> binary pkg relationship 79 // with a java binary signature package and a more authoritative JVM release package. 80 func identifyOverlappingJVMRelationship(parent *pkg.Package, child *pkg.Package) artifact.ID { 81 if !slices.Contains(binaryCatalogerTypes, parent.Type) { 82 return "" 83 } 84 85 if !slices.Contains(binaryCatalogerTypes, child.Type) { 86 return "" 87 } 88 89 if child.Metadata == nil { 90 return "" 91 } 92 93 var ( 94 foundJVM bool 95 idToRemove artifact.ID 96 ) 97 for _, p := range []*pkg.Package{parent, child} { 98 switch p.Metadata.(type) { 99 case pkg.JavaVMInstallation: 100 foundJVM = true 101 default: 102 idToRemove = p.ID() 103 } 104 } 105 106 if foundJVM { 107 return idToRemove 108 } 109 110 return "" 111 } 112 113 // identifyOverlappingOSRelationship indicates the package ID to remove if this is an OS pkg -> bin pkg relationship. 114 // This was implemented as a way to help resolve: https://github.com/anchore/syft/issues/931 115 func identifyOverlappingOSRelationship(parent *pkg.Package, child *pkg.Package) artifact.ID { 116 if !slices.Contains(osCatalogerTypes, parent.Type) { 117 return "" 118 } 119 120 if slices.Contains(binaryCatalogerTypes, child.Type) { 121 return child.ID() 122 } 123 124 if child.Metadata == nil { 125 return "" 126 } 127 128 if !slices.Contains(binaryMetadataTypes, reflect.TypeOf(child.Metadata).Name()) { 129 return "" 130 } 131 132 return child.ID() 133 } 134 135 // identifyOverlappingBitnamiRelationship indicates the package ID to remove if this is a Bitnami pkg -> bin pkg relationship. 136 func identifyOverlappingBitnamiRelationship(parent *pkg.Package, child *pkg.Package) artifact.ID { 137 if !slices.Contains(bitnamiCatalogerTypes, parent.Type) { 138 return "" 139 } 140 141 if slices.Contains(binaryCatalogerTypes, child.Type) { 142 return child.ID() 143 } 144 145 if child.Metadata == nil { 146 return "" 147 } 148 149 if !slices.Contains(binaryMetadataTypes, reflect.TypeOf(child.Metadata).Name()) { 150 return "" 151 } 152 153 return child.ID() 154 }