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

refactor(sbom): simplify relationship generation #7985

Merged
merged 1 commit into from
Nov 28, 2024
Merged
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
55 changes: 20 additions & 35 deletions pkg/sbom/io/encode.go
Original file line number Diff line number Diff line change
Expand Up @@ -196,9 +196,6 @@ func (e *Encoder) encodePackages(parent *core.Component, result types.Result) {
vulns[vuln.PkgIdentifier.UID] = append(vulns[vuln.PkgIdentifier.UID], v)
}

// Convert packages into components and add them to the BOM
parentRelationship := core.RelationshipContains

// UID => Package Component
components := make(map[string]*core.Component, len(result.Packages))
// PkgID => Package Component
Expand All @@ -222,27 +219,15 @@ func (e *Encoder) encodePackages(parent *core.Component, result types.Result) {
if vv := vulns[pkg.Identifier.UID]; vv != nil {
e.bom.AddVulnerabilities(c, vv)
}

// Handle a root package
if pkg.Relationship == ftypes.RelationshipRoot {
// If the package is a root package, add a relationship between the parent and the root package
e.bom.AddRelationship(parent, c, core.RelationshipContains)
// Replace the parent with the root package
parent = c
parentRelationship = core.RelationshipDependsOn
}
}

// Build a dependency graph between packages
for _, pkg := range result.Packages {
if pkg.Relationship == ftypes.RelationshipRoot {
continue
}
c := components[pkg.Identifier.UID]

// Add a relationship between the parent and the package if needed
if e.belongToParent(pkg, parents) {
e.bom.AddRelationship(parent, c, parentRelationship)
e.bom.AddRelationship(parent, c, core.RelationshipContains)
}

// Add relationships between the package and its dependencies
Expand Down Expand Up @@ -419,30 +404,30 @@ func (*Encoder) vulnerability(vuln types.DetectedVulnerability) core.Vulnerabili

// belongToParent determines if a package should be directly included in the parent based on its relationship and dependencies.
func (*Encoder) belongToParent(pkg ftypes.Package, parents map[string]ftypes.Packages) bool {
// Case 1: Direct/Indirect: known , DependsOn: known
// 1-1: Only direct packages are included in the parent (RelationshipContains or RelationshipDependsOn)
// 1-2: Each direct package includes its dependent packages (RelationshipDependsOn).
// Case 2: Direct/Indirect: unknown, DependsOn: unknown (e.g., conan lockfile v2)
// All packages are included in the parent (RelationshipContains or RelationshipDependsOn).
// Case 3: Direct/Indirect: unknown, DependsOn: known (e.g., OS packages)
// All packages are included in the parent (RelationshipContains or RelationshipDependsOn).
// Case 4: Direct/Indirect: known , DependsOn: unknown (e.g., go.mod without $GOPATH)
// All packages are included in the parent (RelationshipContains or RelationshipDependsOn).
// Case 1: Relationship: known , DependsOn: known
// Packages with no parent are included in the parent
// - Relationship:
// - Root: true (it doesn't have a parent)
// - Workspace: false (it always has a parent)
// - Direct:
// - Under Root or Workspace: false (it always has a parent)
// - No parents: true (e.g., package-lock.json)
// - Indirect: false (it always has a parent)
// Case 2: Relationship: unknown, DependsOn: unknown (e.g., conan lockfile v2)
// All packages are included in the parent
// Case 3: Relationship: known , DependsOn: unknown (e.g., go.mod without $GOPATH)
// All packages are included in the parent
// Case 4: Relationship: unknown, DependsOn: known (e.g., OS packages)
// All packages are included in the parent even if they have parents
switch {
// Case 1-1: direct packages
case pkg.Relationship == ftypes.RelationshipDirect:
// Case 1, 2 and 3
case len(parents[pkg.ID]) == 0:
return true
// Case 1-2: indirect packages
case pkg.Relationship == ftypes.RelationshipIndirect && len(parents[pkg.ID]) != 0:
return false
// Case 2 & 3:
// Case 4
case pkg.Relationship == ftypes.RelationshipUnknown:
return true
// Case 4:
case pkg.Relationship == ftypes.RelationshipIndirect && len(parents[pkg.ID]) == 0:
return true
default:
return true
return false
}
}

Expand Down
1 change: 1 addition & 0 deletions pkg/sbom/io/encode_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,7 @@ func TestEncoder_Encode(t *testing.T) {
Relationship: ftypes.RelationshipRoot,
DependsOn: []string{
"github.com/org/[email protected]",
"[email protected]",
},
},
{
Expand Down