migrate pkg.ID and pkg.Relationship to artifact package

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
This commit is contained in:
Alex Goodman 2021-11-08 15:53:28 -05:00
parent 9bbc9ff633
commit a906b9a03a
No known key found for this signature in database
GPG Key ID: 5CB45AE22BAB7EA7
11 changed files with 75 additions and 60 deletions

View File

@ -3,6 +3,8 @@ package syftjson
import ( import (
"fmt" "fmt"
"github.com/anchore/syft/syft/artifact"
"github.com/anchore/syft/syft/sbom" "github.com/anchore/syft/syft/sbom"
"github.com/anchore/syft/internal" "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)) result := make([]model.Relationship, len(relationships))
for i, r := range relationships { for i, r := range relationships {
result[i] = model.Relationship{ result[i] = model.Relationship{
Parent: string(r.Parent), Parent: string(r.From),
Child: string(r.Child), Child: string(r.To),
Type: string(r.Type), Type: string(r.Type),
Metadata: r.Metadata, Metadata: r.Data,
} }
} }
return result return result

View File

@ -3,6 +3,7 @@ package syftjson
import ( import (
"github.com/anchore/syft/internal/formats/syftjson/model" "github.com/anchore/syft/internal/formats/syftjson/model"
"github.com/anchore/syft/internal/log" "github.com/anchore/syft/internal/log"
"github.com/anchore/syft/syft/artifact"
"github.com/anchore/syft/syft/distro" "github.com/anchore/syft/syft/distro"
"github.com/anchore/syft/syft/pkg" "github.com/anchore/syft/syft/pkg"
"github.com/anchore/syft/syft/sbom" "github.com/anchore/syft/syft/sbom"
@ -61,7 +62,7 @@ func toSyftPackage(p model.Package) pkg.Package {
} }
return pkg.Package{ return pkg.Package{
ID: pkg.ID(p.ID), ID: artifact.ID(p.ID),
Name: p.Name, Name: p.Name,
Version: p.Version, Version: p.Version,
FoundBy: p.FoundBy, FoundBy: p.FoundBy,

View File

@ -1,4 +1,4 @@
package pkg package artifact
// ID represents a unique value for each package added to a package catalog. // ID represents a unique value for each package added to a package catalog.
type ID string type ID string

View File

@ -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{}
}

View File

@ -4,6 +4,8 @@ import (
"sort" "sort"
"sync" "sync"
"github.com/anchore/syft/syft/artifact"
"github.com/anchore/syft/internal" "github.com/anchore/syft/internal"
"github.com/anchore/syft/internal/log" "github.com/anchore/syft/internal/log"
@ -11,18 +13,18 @@ import (
// Catalog represents a collection of Packages. // Catalog represents a collection of Packages.
type Catalog struct { type Catalog struct {
byID map[ID]*Package byID map[artifact.ID]*Package
idsByType map[Type][]ID idsByType map[Type][]artifact.ID
idsByPath map[string][]ID // note: this is real path or virtual path idsByPath map[string][]artifact.ID // note: this is real path or virtual path
lock sync.RWMutex lock sync.RWMutex
} }
// NewCatalog returns a new empty Catalog // NewCatalog returns a new empty Catalog
func NewCatalog(pkgs ...Package) *Catalog { func NewCatalog(pkgs ...Package) *Catalog {
catalog := Catalog{ catalog := Catalog{
byID: make(map[ID]*Package), byID: make(map[artifact.ID]*Package),
idsByType: make(map[Type][]ID), idsByType: make(map[Type][]artifact.ID),
idsByPath: make(map[string][]ID), idsByPath: make(map[string][]artifact.ID),
} }
for _, p := range pkgs { for _, p := range pkgs {
@ -38,7 +40,7 @@ func (c *Catalog) PackageCount() int {
} }
// Package returns the package with the given ID. // 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] v, exists := c.byID[id]
if !exists { if !exists {
return nil return nil
@ -52,7 +54,7 @@ func (c *Catalog) PackagesByPath(path string) []*Package {
} }
// Packages returns all packages for the given ID. // 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 { for _, i := range ids {
p, exists := c.byID[i] p, exists := c.byID[i]
if exists { if exists {
@ -74,7 +76,7 @@ func (c *Catalog) Add(p Package) {
return return
} }
p.ID = ID(fingerprint) p.ID = artifact.ID(fingerprint)
} }
// store by package ID // 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() c.lock.Lock()
defer c.lock.Unlock() defer c.lock.Unlock()
@ -177,7 +179,7 @@ func (c *Catalog) Sorted(types ...Type) []*Package {
return pkgs 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 { for _, value := range target {
if value != id { if value != id {
result = append(result, value) result = append(result, value)

View File

@ -3,6 +3,8 @@ package pkg
import ( import (
"testing" "testing"
"github.com/anchore/syft/syft/artifact"
"github.com/scylladb/go-set/strset" "github.com/scylladb/go-set/strset"
"github.com/anchore/syft/syft/source" "github.com/anchore/syft/syft/source"
@ -84,7 +86,7 @@ func TestCatalogRemove(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
pkgs []Package pkgs []Package
removeId ID removeId artifact.ID
expectedIndexes expectedIndexes expectedIndexes expectedIndexes
}{ }{
{ {

View File

@ -2,6 +2,7 @@ package pkg
import ( import (
"github.com/anchore/syft/internal/log" "github.com/anchore/syft/internal/log"
"github.com/anchore/syft/syft/artifact"
"github.com/bmatcuk/doublestar/v2" "github.com/bmatcuk/doublestar/v2"
"github.com/scylladb/go-set/strset" "github.com/scylladb/go-set/strset"
) )
@ -20,17 +21,17 @@ type ownershipByFilesMetadata struct {
Files []string `json:"files"` Files []string `json:"files"`
} }
func ownershipByFilesRelationships(catalog *Catalog) []Relationship { func ownershipByFilesRelationships(catalog *Catalog) []artifact.Relationship {
var relationships = findOwnershipByFilesRelationships(catalog) var relationships = findOwnershipByFilesRelationships(catalog)
var edges []Relationship var edges []artifact.Relationship
for parent, children := range relationships { for parent, children := range relationships {
for child, files := range children { for child, files := range children {
edges = append(edges, Relationship{ edges = append(edges, artifact.Relationship{
Parent: parent, From: parent,
Child: child, To: child,
Type: OwnershipByFileOverlapRelationship, Type: artifact.OwnershipByFileOverlapRelationship,
Metadata: ownershipByFilesMetadata{ Data: ownershipByFilesMetadata{
Files: files.List(), 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 // 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[]). // 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 { func findOwnershipByFilesRelationships(catalog *Catalog) map[artifact.ID]map[artifact.ID]*strset.Set {
var relationships = make(map[ID]map[ID]*strset.Set) var relationships = make(map[artifact.ID]map[artifact.ID]*strset.Set)
if catalog == nil { if catalog == nil {
return relationships return relationships
@ -72,7 +73,7 @@ func findOwnershipByFilesRelationships(catalog *Catalog) map[ID]map[ID]*strset.S
continue continue
} }
if _, exists := relationships[candidateOwnerPkg.ID]; !exists { 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 { if _, exists := relationships[candidateOwnerPkg.ID][subPackage.ID]; !exists {

View File

@ -3,6 +3,8 @@ package pkg
import ( import (
"testing" "testing"
"github.com/anchore/syft/syft/artifact"
"github.com/anchore/syft/syft/source" "github.com/anchore/syft/syft/source"
"github.com/go-test/deep" "github.com/go-test/deep"
) )
@ -11,7 +13,7 @@ func TestOwnershipByFilesRelationship(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
pkgs []Package pkgs []Package
expectedRelations []Relationship expectedRelations []artifact.Relationship
}{ }{
{ {
name: "owns-by-real-path", name: "owns-by-real-path",
@ -53,12 +55,12 @@ func TestOwnershipByFilesRelationship(t *testing.T) {
Type: NpmPkg, Type: NpmPkg,
}, },
}, },
expectedRelations: []Relationship{ expectedRelations: []artifact.Relationship{
{ {
Parent: "parent", From: "parent",
Child: "child", To: "child",
Type: OwnershipByFileOverlapRelationship, Type: artifact.OwnershipByFileOverlapRelationship,
Metadata: ownershipByFilesMetadata{ Data: ownershipByFilesMetadata{
Files: []string{ Files: []string{
"/d/path", "/d/path",
}, },
@ -106,12 +108,12 @@ func TestOwnershipByFilesRelationship(t *testing.T) {
Type: NpmPkg, Type: NpmPkg,
}, },
}, },
expectedRelations: []Relationship{ expectedRelations: []artifact.Relationship{
{ {
Parent: "parent", From: "parent",
Child: "child", To: "child",
Type: OwnershipByFileOverlapRelationship, Type: artifact.OwnershipByFileOverlapRelationship,
Metadata: ownershipByFilesMetadata{ Data: ownershipByFilesMetadata{
Files: []string{ Files: []string{
"/another/path", "/another/path",
}, },

View File

@ -6,6 +6,8 @@ package pkg
import ( import (
"fmt" "fmt"
"github.com/anchore/syft/syft/artifact"
"github.com/anchore/syft/syft/source" "github.com/anchore/syft/syft/source"
"github.com/mitchellh/hashstructure" "github.com/mitchellh/hashstructure"
) )
@ -13,7 +15,7 @@ import (
// Package represents an application or library that has been bundled into a distributable format. // 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? // TODO: if we ignore FoundBy for ID generation should we merge the field to show it was found in two places?
type Package struct { 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 Name string // the package name
Version string // the version of the package Version string // the version of the package
FoundBy string // the specific cataloger that discovered this package FoundBy string // the specific cataloger that discovered this package

View File

@ -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)
}

View File

@ -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)
}