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  }