github.com/anchore/syft@v1.38.2/syft/sbom/sbom.go (about) 1 package sbom 2 3 import ( 4 "slices" 5 "sort" 6 7 "github.com/anchore/syft/internal/log" 8 "github.com/anchore/syft/syft/artifact" 9 "github.com/anchore/syft/syft/file" 10 "github.com/anchore/syft/syft/linux" 11 "github.com/anchore/syft/syft/pkg" 12 "github.com/anchore/syft/syft/source" 13 ) 14 15 type SBOM struct { 16 Artifacts Artifacts 17 Relationships []artifact.Relationship 18 Source source.Description 19 Descriptor Descriptor 20 } 21 22 type Artifacts struct { 23 Packages *pkg.Collection 24 FileMetadata map[file.Coordinates]file.Metadata 25 FileDigests map[file.Coordinates][]file.Digest 26 FileContents map[file.Coordinates]string 27 FileLicenses map[file.Coordinates][]file.License 28 Executables map[file.Coordinates]file.Executable 29 Unknowns map[file.Coordinates][]string 30 LinuxDistribution *linux.Release 31 } 32 33 type Descriptor struct { 34 Name string 35 Version string 36 Configuration interface{} 37 } 38 39 // RelationshipsSorted returns a sorted slice of all relationships 40 // Deprecated -- use relationship.Index 41 func (s SBOM) RelationshipsSorted() []artifact.Relationship { 42 relationships := s.Relationships 43 sort.SliceStable(relationships, func(i, j int) bool { 44 if relationships[i].From.ID() == relationships[j].From.ID() { 45 if relationships[i].To.ID() == relationships[j].To.ID() { 46 return relationships[i].Type < relationships[j].Type 47 } 48 return relationships[i].To.ID() < relationships[j].To.ID() 49 } 50 return relationships[i].From.ID() < relationships[j].From.ID() 51 }) 52 return relationships 53 } 54 55 func (s SBOM) AllCoordinates() []file.Coordinates { 56 set := file.NewCoordinateSet() 57 for coordinates := range s.Artifacts.FileMetadata { 58 set.Add(coordinates) 59 } 60 for coordinates := range s.Artifacts.FileContents { 61 set.Add(coordinates) 62 } 63 for coordinates := range s.Artifacts.FileDigests { 64 set.Add(coordinates) 65 } 66 for coordinates := range s.Artifacts.Unknowns { 67 set.Add(coordinates) 68 } 69 for _, relationship := range s.Relationships { 70 for _, coordinates := range extractCoordinates(relationship) { 71 set.Add(coordinates) 72 } 73 } 74 return set.ToSlice() 75 } 76 77 // RelationshipsForPackage returns all relationships for the provided types. 78 // If no types are provided, all relationships for the package are returned. 79 // Deprecated -- use relationship.Index 80 func (s SBOM) RelationshipsForPackage(p pkg.Package, rt ...artifact.RelationshipType) []artifact.Relationship { 81 if len(rt) == 0 { 82 rt = artifact.AllRelationshipTypes() 83 } 84 85 pID := p.ID() 86 87 var relationships []artifact.Relationship 88 for _, relationship := range s.Relationships { 89 if relationship.From == nil || relationship.To == nil { 90 log.Debugf("relationship has nil edge, skipping: %#v", relationship) 91 continue 92 } 93 fromID := relationship.From.ID() 94 toID := relationship.To.ID() 95 hasPkgID := fromID == pID || toID == pID 96 97 if !hasPkgID { 98 continue 99 } 100 101 // check if the relationship is one we're searching for; rt is inclusive 102 if !slices.ContainsFunc(rt, func(r artifact.RelationshipType) bool { return relationship.Type == r }) { 103 continue 104 } 105 relationships = append(relationships, relationship) 106 } 107 108 return relationships 109 } 110 111 // CoordinatesForPackage returns all coordinates for the provided package for provided relationship types 112 // If no types are provided, all relationship types are considered. 113 // Deprecated -- use relationship.Index 114 func (s SBOM) CoordinatesForPackage(p pkg.Package, rt ...artifact.RelationshipType) []file.Coordinates { 115 var coordinates []file.Coordinates 116 for _, relationship := range s.RelationshipsForPackage(p, rt...) { 117 cords := extractCoordinates(relationship) 118 coordinates = append(coordinates, cords...) 119 } 120 return coordinates 121 } 122 123 func extractCoordinates(relationship artifact.Relationship) (results []file.Coordinates) { 124 if coordinates, exists := relationship.From.(file.Coordinates); exists { 125 results = append(results, coordinates) 126 } 127 128 if coordinates, exists := relationship.To.(file.Coordinates); exists { 129 results = append(results, coordinates) 130 } 131 132 return results 133 }