diff --git a/internal/formats/syftjson/to_format_model.go b/internal/formats/syftjson/to_format_model.go index 1b2a7ca48..972ce224e 100644 --- a/internal/formats/syftjson/to_format_model.go +++ b/internal/formats/syftjson/to_format_model.go @@ -3,6 +3,8 @@ package syftjson import ( "fmt" + "github.com/anchore/syft/syft/artifact" + "github.com/anchore/syft/syft/sbom" "github.com/anchore/syft/internal" @@ -87,14 +89,14 @@ func toPackageModel(p *pkg.Package) model.Package { } } -func toRelationshipModel(relationships []pkg.Relationship) []model.Relationship { +func toRelationshipModel(relationships []artifact.Relationship) []model.Relationship { result := make([]model.Relationship, len(relationships)) for i, r := range relationships { result[i] = model.Relationship{ - Parent: string(r.Parent), - Child: string(r.Child), + Parent: string(r.From), + Child: string(r.To), Type: string(r.Type), - Metadata: r.Metadata, + Metadata: r.Data, } } return result diff --git a/internal/formats/syftjson/to_syft_model.go b/internal/formats/syftjson/to_syft_model.go index e2c6ee40c..f9f75d10f 100644 --- a/internal/formats/syftjson/to_syft_model.go +++ b/internal/formats/syftjson/to_syft_model.go @@ -3,6 +3,7 @@ package syftjson import ( "github.com/anchore/syft/internal/formats/syftjson/model" "github.com/anchore/syft/internal/log" + "github.com/anchore/syft/syft/artifact" "github.com/anchore/syft/syft/distro" "github.com/anchore/syft/syft/pkg" "github.com/anchore/syft/syft/sbom" @@ -61,7 +62,7 @@ func toSyftPackage(p model.Package) pkg.Package { } return pkg.Package{ - ID: pkg.ID(p.ID), + ID: artifact.ID(p.ID), Name: p.Name, Version: p.Version, FoundBy: p.FoundBy, diff --git a/syft/pkg/id.go b/syft/artifact/id.go similarity index 84% rename from syft/pkg/id.go rename to syft/artifact/id.go index 7b3e6b2d7..890e4b4ef 100644 --- a/syft/pkg/id.go +++ b/syft/artifact/id.go @@ -1,4 +1,4 @@ -package pkg +package artifact // ID represents a unique value for each package added to a package catalog. type ID string diff --git a/syft/artifact/relationship.go b/syft/artifact/relationship.go new file mode 100644 index 000000000..adc867b57 --- /dev/null +++ b/syft/artifact/relationship.go @@ -0,0 +1,15 @@ +package artifact + +const ( + // OwnershipByFileOverlapRelationship indicates that the parent package owns the child package made evident by the set of provided files + OwnershipByFileOverlapRelationship RelationshipType = "ownership-by-file-overlap" +) + +type RelationshipType string + +type Relationship struct { + From ID + To ID + Type RelationshipType + Data interface{} +} diff --git a/syft/pkg/catalog.go b/syft/pkg/catalog.go index 66c37c9c3..d3fbae63a 100644 --- a/syft/pkg/catalog.go +++ b/syft/pkg/catalog.go @@ -4,6 +4,8 @@ import ( "sort" "sync" + "github.com/anchore/syft/syft/artifact" + "github.com/anchore/syft/internal" "github.com/anchore/syft/internal/log" @@ -11,18 +13,18 @@ import ( // Catalog represents a collection of Packages. type Catalog struct { - byID map[ID]*Package - idsByType map[Type][]ID - idsByPath map[string][]ID // note: this is real path or virtual path + byID map[artifact.ID]*Package + idsByType map[Type][]artifact.ID + idsByPath map[string][]artifact.ID // note: this is real path or virtual path lock sync.RWMutex } // NewCatalog returns a new empty Catalog func NewCatalog(pkgs ...Package) *Catalog { catalog := Catalog{ - byID: make(map[ID]*Package), - idsByType: make(map[Type][]ID), - idsByPath: make(map[string][]ID), + byID: make(map[artifact.ID]*Package), + idsByType: make(map[Type][]artifact.ID), + idsByPath: make(map[string][]artifact.ID), } for _, p := range pkgs { @@ -38,7 +40,7 @@ func (c *Catalog) PackageCount() int { } // Package returns the package with the given ID. -func (c *Catalog) Package(id ID) *Package { +func (c *Catalog) Package(id artifact.ID) *Package { v, exists := c.byID[id] if !exists { return nil @@ -52,7 +54,7 @@ func (c *Catalog) PackagesByPath(path string) []*Package { } // Packages returns all packages for the given ID. -func (c *Catalog) Packages(ids []ID) (result []*Package) { +func (c *Catalog) Packages(ids []artifact.ID) (result []*Package) { for _, i := range ids { p, exists := c.byID[i] if exists { @@ -74,7 +76,7 @@ func (c *Catalog) Add(p Package) { return } - p.ID = ID(fingerprint) + p.ID = artifact.ID(fingerprint) } // store by package ID @@ -97,7 +99,7 @@ func (c *Catalog) Add(p Package) { } } -func (c *Catalog) Remove(id ID) { +func (c *Catalog) Remove(id artifact.ID) { c.lock.Lock() defer c.lock.Unlock() @@ -177,7 +179,7 @@ func (c *Catalog) Sorted(types ...Type) []*Package { return pkgs } -func removeID(id ID, target []ID) (result []ID) { +func removeID(id artifact.ID, target []artifact.ID) (result []artifact.ID) { for _, value := range target { if value != id { result = append(result, value) diff --git a/syft/pkg/catalog_test.go b/syft/pkg/catalog_test.go index a11c238ae..52c671bbf 100644 --- a/syft/pkg/catalog_test.go +++ b/syft/pkg/catalog_test.go @@ -3,6 +3,8 @@ package pkg import ( "testing" + "github.com/anchore/syft/syft/artifact" + "github.com/scylladb/go-set/strset" "github.com/anchore/syft/syft/source" @@ -84,7 +86,7 @@ func TestCatalogRemove(t *testing.T) { tests := []struct { name string pkgs []Package - removeId ID + removeId artifact.ID expectedIndexes expectedIndexes }{ { diff --git a/syft/pkg/ownership_by_files_relationship.go b/syft/pkg/ownership_by_files_relationship.go index 3aa2f37b7..90cc31c49 100644 --- a/syft/pkg/ownership_by_files_relationship.go +++ b/syft/pkg/ownership_by_files_relationship.go @@ -2,6 +2,7 @@ package pkg import ( "github.com/anchore/syft/internal/log" + "github.com/anchore/syft/syft/artifact" "github.com/bmatcuk/doublestar/v2" "github.com/scylladb/go-set/strset" ) @@ -20,17 +21,17 @@ type ownershipByFilesMetadata struct { Files []string `json:"files"` } -func ownershipByFilesRelationships(catalog *Catalog) []Relationship { +func ownershipByFilesRelationships(catalog *Catalog) []artifact.Relationship { var relationships = findOwnershipByFilesRelationships(catalog) - var edges []Relationship + var edges []artifact.Relationship for parent, children := range relationships { for child, files := range children { - edges = append(edges, Relationship{ - Parent: parent, - Child: child, - Type: OwnershipByFileOverlapRelationship, - Metadata: ownershipByFilesMetadata{ + edges = append(edges, artifact.Relationship{ + From: parent, + To: child, + Type: artifact.OwnershipByFileOverlapRelationship, + Data: ownershipByFilesMetadata{ Files: files.List(), }, }) @@ -42,8 +43,8 @@ func ownershipByFilesRelationships(catalog *Catalog) []Relationship { // findOwnershipByFilesRelationships find overlaps in file ownership with a file that defines another package. Specifically, a .Location.Path of // a package is found to be owned by another (from the owner's .Metadata.Files[]). -func findOwnershipByFilesRelationships(catalog *Catalog) map[ID]map[ID]*strset.Set { - var relationships = make(map[ID]map[ID]*strset.Set) +func findOwnershipByFilesRelationships(catalog *Catalog) map[artifact.ID]map[artifact.ID]*strset.Set { + var relationships = make(map[artifact.ID]map[artifact.ID]*strset.Set) if catalog == nil { return relationships @@ -72,7 +73,7 @@ func findOwnershipByFilesRelationships(catalog *Catalog) map[ID]map[ID]*strset.S continue } if _, exists := relationships[candidateOwnerPkg.ID]; !exists { - relationships[candidateOwnerPkg.ID] = make(map[ID]*strset.Set) + relationships[candidateOwnerPkg.ID] = make(map[artifact.ID]*strset.Set) } if _, exists := relationships[candidateOwnerPkg.ID][subPackage.ID]; !exists { diff --git a/syft/pkg/ownership_by_files_relationship_test.go b/syft/pkg/ownership_by_files_relationship_test.go index 3e8bf4597..463286989 100644 --- a/syft/pkg/ownership_by_files_relationship_test.go +++ b/syft/pkg/ownership_by_files_relationship_test.go @@ -3,6 +3,8 @@ package pkg import ( "testing" + "github.com/anchore/syft/syft/artifact" + "github.com/anchore/syft/syft/source" "github.com/go-test/deep" ) @@ -11,7 +13,7 @@ func TestOwnershipByFilesRelationship(t *testing.T) { tests := []struct { name string pkgs []Package - expectedRelations []Relationship + expectedRelations []artifact.Relationship }{ { name: "owns-by-real-path", @@ -53,12 +55,12 @@ func TestOwnershipByFilesRelationship(t *testing.T) { Type: NpmPkg, }, }, - expectedRelations: []Relationship{ + expectedRelations: []artifact.Relationship{ { - Parent: "parent", - Child: "child", - Type: OwnershipByFileOverlapRelationship, - Metadata: ownershipByFilesMetadata{ + From: "parent", + To: "child", + Type: artifact.OwnershipByFileOverlapRelationship, + Data: ownershipByFilesMetadata{ Files: []string{ "/d/path", }, @@ -106,12 +108,12 @@ func TestOwnershipByFilesRelationship(t *testing.T) { Type: NpmPkg, }, }, - expectedRelations: []Relationship{ + expectedRelations: []artifact.Relationship{ { - Parent: "parent", - Child: "child", - Type: OwnershipByFileOverlapRelationship, - Metadata: ownershipByFilesMetadata{ + From: "parent", + To: "child", + Type: artifact.OwnershipByFileOverlapRelationship, + Data: ownershipByFilesMetadata{ Files: []string{ "/another/path", }, diff --git a/syft/pkg/package.go b/syft/pkg/package.go index 08c5ebbdb..8bd92b260 100644 --- a/syft/pkg/package.go +++ b/syft/pkg/package.go @@ -6,6 +6,8 @@ package pkg import ( "fmt" + "github.com/anchore/syft/syft/artifact" + "github.com/anchore/syft/syft/source" "github.com/mitchellh/hashstructure" ) @@ -13,7 +15,7 @@ import ( // Package represents an application or library that has been bundled into a distributable format. // TODO: if we ignore FoundBy for ID generation should we merge the field to show it was found in two places? type Package struct { - ID ID `hash:"ignore"` // uniquely identifies a package, set by the cataloger + ID artifact.ID `hash:"ignore"` // uniquely identifies a package, set by the cataloger Name string // the package name Version string // the version of the package FoundBy string // the specific cataloger that discovered this package diff --git a/syft/pkg/relationship.go b/syft/pkg/relationship.go deleted file mode 100644 index 09271e564..000000000 --- a/syft/pkg/relationship.go +++ /dev/null @@ -1,20 +0,0 @@ -package pkg - -const ( - // OwnershipByFileOverlapRelationship indicates that the parent package owns the child package made evident by the set of provided files - OwnershipByFileOverlapRelationship RelationshipType = "ownership-by-file-overlap" -) - -type RelationshipType string - -type Relationship struct { - Parent ID - Child ID - Type RelationshipType - Metadata interface{} -} - -// TODO: as more relationships are added, this function signature will probably accommodate selection -func NewRelationships(catalog *Catalog) []Relationship { - return ownershipByFilesRelationships(catalog) -} diff --git a/syft/pkg/relationships.go b/syft/pkg/relationships.go new file mode 100644 index 000000000..f0acd7c92 --- /dev/null +++ b/syft/pkg/relationships.go @@ -0,0 +1,8 @@ +package pkg + +import "github.com/anchore/syft/syft/artifact" + +// TODO: as more relationships are added, this function signature will probably accommodate selection +func NewRelationships(catalog *Catalog) []artifact.Relationship { + return ownershipByFilesRelationships(catalog) +}