Skip to content

Commit

Permalink
refactor(sbom): simplify relationship generation (#7985)
Browse files Browse the repository at this point in the history
Signed-off-by: knqyf263 <knqyf263@gmail.com>
  • Loading branch information
knqyf263 authored Nov 28, 2024
1 parent c238c51 commit 0627992
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 35 deletions.
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/direct@v1.0.0",
"stdlib@v1.22.1",
},
},
{
Expand Down

0 comments on commit 0627992

Please sign in to comment.