mirror of
https://github.com/anchore/syft.git
synced 2025-11-18 00:43:20 +01:00
migrate pkg.ID and pkg.Relationship to artifact package
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
This commit is contained in:
parent
9bbc9ff633
commit
a906b9a03a
@ -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
|
||||||
|
|||||||
@ -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,
|
||||||
|
|||||||
@ -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
|
||||||
15
syft/artifact/relationship.go
Normal file
15
syft/artifact/relationship.go
Normal 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{}
|
||||||
|
}
|
||||||
@ -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)
|
||||||
|
|||||||
@ -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
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
|
|||||||
@ -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 {
|
||||||
|
|||||||
@ -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",
|
||||||
},
|
},
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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)
|
|
||||||
}
|
|
||||||
8
syft/pkg/relationships.go
Normal file
8
syft/pkg/relationships.go
Normal 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)
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user