Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Add component type to pkg #2146

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 27 additions & 2 deletions syft/formats/common/cyclonedxhelpers/format.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ func ToFormatModel(s sbom.SBOM) *cyclonedx.BOM {
components = append(components, toOSComponent(s.Artifacts.LinuxDistribution)...)
cdxBOM.Components = &components

dependencies := toDependencies(s.Relationships)
dependencies := toDependencies(packages, s.Relationships, cdxBOM.Metadata)
if len(dependencies) > 0 {
cdxBOM.Dependencies = &dependencies
}
Expand Down Expand Up @@ -138,9 +138,34 @@ func isExpressiblePackageRelationship(ty artifact.RelationshipType) bool {
return false
}
}
func toRootDependency(packages []pkg.Package, metadata *cyclonedx.Metadata) (dep cyclonedx.Dependency) {
if metadata.Component == nil {
return dep
}
topLevelDeps := []string{}
topLevelBomRef := metadata.Component.BOMRef

for _, p := range packages {
if p.ComponentType == pkg.ComponentTypeApplication {
topLevelDeps = append(topLevelDeps, deriveBomRef(p))
}
}

dep = cyclonedx.Dependency{
Ref: topLevelBomRef,
Dependencies: &topLevelDeps,
}
return dep
}

func toDependencies(relationships []artifact.Relationship) []cyclonedx.Dependency {
func toDependencies(packages []pkg.Package, relationships []artifact.Relationship, metadata *cyclonedx.Metadata) []cyclonedx.Dependency {
dependencies := map[string]*cyclonedx.Dependency{}

rootDependency := toRootDependency(packages, metadata)
if rootDependency.Ref != "" {
dependencies[rootDependency.Ref] = &rootDependency
}

for _, r := range relationships {
exists := isExpressiblePackageRelationship(r.Type)
if !exists {
Expand Down
19 changes: 18 additions & 1 deletion syft/formats/common/cyclonedxhelpers/format_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"github.com/anchore/syft/syft/artifact"
"github.com/anchore/syft/syft/pkg"
"github.com/anchore/syft/syft/sbom"
"github.com/anchore/syft/syft/source"
)

func Test_formatCPE(t *testing.T) {
Expand Down Expand Up @@ -42,7 +43,8 @@ func Test_formatCPE(t *testing.T) {

func Test_relationships(t *testing.T) {
p1 := pkg.Package{
Name: "p1",
Name: "p1",
ComponentType: pkg.ComponentTypeApplication,
}

p2 := pkg.Package{
Expand Down Expand Up @@ -70,6 +72,15 @@ func Test_relationships(t *testing.T) {
{
name: "package dependencyOf relationships output as dependencies",
sbom: sbom.SBOM{
Descriptor: sbom.Descriptor{
Name: "syft",
Version: "1.2.3",
},
Source: source.Description{
Name: "test",
Version: "1.2.3",
Metadata: source.DirectorySourceMetadata{Path: "some/path/to/place"},
},
Artifacts: sbom.Artifacts{
Packages: pkg.NewCollection(p1, p2, p3, p4),
},
Expand All @@ -92,6 +103,12 @@ func Test_relationships(t *testing.T) {
},
},
expected: &[]cyclonedx.Dependency{
{
Ref: "7ce954b3d0af7363", // hardcoded root component bom-ref
Dependencies: &[]string{
deriveBomRef(p1),
},
},
{
Ref: deriveBomRef(p1),
Dependencies: &[]string{
Expand Down
8 changes: 8 additions & 0 deletions syft/pkg/component_type.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package pkg

type ComponentType string

const (
ComponentTypeApplication ComponentType = "application"
ComponentTypeLibrary ComponentType = "library"
)
25 changes: 13 additions & 12 deletions syft/pkg/package.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,19 @@ 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 artifact.ID `hash:"ignore"`
Name string // the package name
Version string // the version of the package
FoundBy string `hash:"ignore" cyclonedx:"foundBy"` // the specific cataloger that discovered this package
Locations file.LocationSet // the locations that lead to the discovery of this package (note: this is not necessarily the locations that make up this package)
Licenses LicenseSet // licenses discovered with the package metadata
Language Language `hash:"ignore" cyclonedx:"language"` // the language ecosystem this package belongs to (e.g. JavaScript, Python, etc)
Type Type `cyclonedx:"type"` // the package type (e.g. Npm, Yarn, Python, Rpm, Deb, etc)
CPEs []cpe.CPE `hash:"ignore"` // all possible Common Platform Enumerators (note: this is NOT included in the definition of the ID since all fields on a CPE are derived from other fields)
PURL string `hash:"ignore"` // the Package URL (see https://github.com/package-url/purl-spec)
MetadataType MetadataType `cyclonedx:"metadataType"` // the shape of the additional data in the "metadata" field
Metadata interface{} // additional data found while parsing the package source
id artifact.ID `hash:"ignore"`
Name string // the package name
Version string // the version of the package
FoundBy string `hash:"ignore" cyclonedx:"foundBy"` // the specific cataloger that discovered this package
Locations file.LocationSet // the locations that lead to the discovery of this package (note: this is not necessarily the locations that make up this package)
Licenses LicenseSet // licenses discovered with the package metadata
Language Language `hash:"ignore" cyclonedx:"language"` // the language ecosystem this package belongs to (e.g. JavaScript, Python, etc)
ComponentType ComponentType `cyclonedx:"type"` // the type of component (e.g. application, library, framework, etc)
Type Type // the package type (e.g. Npm, Yarn, Python, Rpm, Deb, etc)
CPEs []cpe.CPE `hash:"ignore"` // all possible Common Platform Enumerators (note: this is NOT included in the definition of the ID since all fields on a CPE are derived from other fields)
PURL string `hash:"ignore"` // the Package URL (see https://github.com/package-url/purl-spec)
MetadataType MetadataType `cyclonedx:"metadataType"` // the shape of the additional data in the "metadata" field
Metadata interface{} // additional data found while parsing the package source
}

func (p *Package) OverrideID(id artifact.ID) {
Expand Down
Loading