Skip to content

Commit

Permalink
CycloneDX SBOM: support nested components (#2156)
Browse files Browse the repository at this point in the history
* CycloneDX SBOM: support nested components

Signed-off-by: mrizzi <mrizzi@redhat.com>

* CycloneDX SBOM: support nested components - more tests

Signed-off-by: mrizzi <mrizzi@redhat.com>

* update sort isDep for unit tests

Signed-off-by: pxp928 <parth.psu@gmail.com>

---------

Signed-off-by: mrizzi <mrizzi@redhat.com>
Signed-off-by: pxp928 <parth.psu@gmail.com>
Co-authored-by: pxp928 <parth.psu@gmail.com>
  • Loading branch information
mrizzi and pxp928 authored Oct 1, 2024
1 parent e39fb22 commit 8cbb091
Show file tree
Hide file tree
Showing 5 changed files with 390 additions and 21 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
{
"bomFormat": "CycloneDX",
"specVersion": "1.4",
"serialNumber": "urn:uuid:c096003c-c9fa-4d9e-9390-fefa51745fe1",
"version": 1,
"metadata": {
"timestamp": "2024-09-24T08:20:03Z",
"component": {
"type": "container",
"name": "quarkus/mandrel-for-jdk-21-rhel8",
"purl": "pkg:oci/mandrel-for-jdk-21-rhel8@sha256%3A41d92dafa5ccbf7f76fa81c5a0e7de83c51166f27bea9b98df018f644016bf04?arch=amd64&os=linux&tag=23.1-13.1724180416"
}
},
"components": [
{
"type": "container",
"bom-ref": "pkg:oci/mandrel-for-jdk-21-rhel8@sha256%3A41d92dafa5ccbf7f76fa81c5a0e7de83c51166f27bea9b98df018f644016bf04?arch=amd64&os=linux&tag=23.1-13.1724180416",
"name": "quarkus/mandrel-for-jdk-21-rhel8",
"version": "sha256:41d92dafa5ccbf7f76fa81c5a0e7de83c51166f27bea9b98df018f644016bf04",
"purl": "pkg:oci/mandrel-for-jdk-21-rhel8@sha256%3A41d92dafa5ccbf7f76fa81c5a0e7de83c51166f27bea9b98df018f644016bf04?arch=amd64&os=linux&tag=23.1-13.1724180416"
},
{
"type": "library",
"bom-ref": "pkg:rpm/redhat/abattis-cantarell-fonts@0.0.25-6.el8?arch=noarch",
"publisher": "Red Hat, Inc.",
"name": "abattis-cantarell-fonts",
"version": "0.0.25-6.el8",
"purl": "pkg:rpm/redhat/abattis-cantarell-fonts@0.0.25-6.el8?arch=noarch",
"properties": [
{
"name": "sbomer:package:type",
"value": "rpm"
},
{
"name": "sbomer:location:0:path",
"value": "/var/lib/rpm/Packages"
}
]
},
{
"type": "library",
"bom-ref": "pkg:maven/compiler/compiler@23.1.4.0-1-redhat-00001?type=jar",
"name": "compiler",
"version": "23.1.4.0-1-redhat-00001",
"purl": "pkg:maven/compiler/compiler@23.1.4.0-1-redhat-00001?type=jar",
"externalReferences": [
{
"type": "build-meta",
"url": "",
"hashes": [
{
"alg": "SHA-1",
"content": "e96edb6e7bab65204479c293378a7485ae2d1c8f"
}
]
}
],
"properties": [
{
"name": "sbomer:package:language",
"value": "java"
},
{
"name": "sbomer:package:type",
"value": "java-archive"
},
{
"name": "sbomer:location:0:path",
"value": "/usr/share/java/quarkus-mandrel-java/compiler.jar"
}
]
}
],
"dependencies": [
{
"ref": "pkg:oci/mandrel-for-jdk-21-rhel8@sha256%3A41d92dafa5ccbf7f76fa81c5a0e7de83c51166f27bea9b98df018f644016bf04?arch=amd64&os=linux&tag=23.1-13.1724180416",
"dependsOn": [
"pkg:rpm/redhat/abattis-cantarell-fonts@0.0.25-6.el8?arch=noarch",
"pkg:maven/compiler/compiler@23.1.4.0-1-redhat-00001?type=jar"
]
},
{
"ref": "pkg:rpm/redhat/abattis-cantarell-fonts@0.0.25-6.el8?arch=noarch",
"dependsOn": []
},
{
"ref": "pkg:maven/compiler/compiler@23.1.4.0-1-redhat-00001?type=jar",
"dependsOn": []
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
{
"bomFormat": "CycloneDX",
"specVersion": "1.4",
"serialNumber": "urn:uuid:c096003c-c9fa-4d9e-9390-fefa51745fe1",
"version": 1,
"metadata": {
"timestamp": "2024-09-24T08:20:03Z",
"component": {
"type": "container",
"name": "quarkus/mandrel-for-jdk-21-rhel8",
"purl": "pkg:oci/mandrel-for-jdk-21-rhel8@sha256%3A41d92dafa5ccbf7f76fa81c5a0e7de83c51166f27bea9b98df018f644016bf04?arch=amd64&os=linux&tag=23.1-13.1724180416"
}
},
"components": [
{
"type": "container",
"bom-ref": "pkg:oci/mandrel-for-jdk-21-rhel8@sha256%3A41d92dafa5ccbf7f76fa81c5a0e7de83c51166f27bea9b98df018f644016bf04?arch=amd64&os=linux&tag=23.1-13.1724180416",
"name": "quarkus/mandrel-for-jdk-21-rhel8",
"version": "sha256:41d92dafa5ccbf7f76fa81c5a0e7de83c51166f27bea9b98df018f644016bf04",
"purl": "pkg:oci/mandrel-for-jdk-21-rhel8@sha256%3A41d92dafa5ccbf7f76fa81c5a0e7de83c51166f27bea9b98df018f644016bf04?arch=amd64&os=linux&tag=23.1-13.1724180416",
"components": [
{
"type": "library",
"bom-ref": "pkg:rpm/redhat/abattis-cantarell-fonts@0.0.25-6.el8?arch=noarch",
"publisher": "Red Hat, Inc.",
"name": "abattis-cantarell-fonts",
"version": "0.0.25-6.el8",
"purl": "pkg:rpm/redhat/abattis-cantarell-fonts@0.0.25-6.el8?arch=noarch",
"properties": [
{
"name": "sbomer:package:type",
"value": "rpm"
},
{
"name": "sbomer:location:0:path",
"value": "/var/lib/rpm/Packages"
}
]
},
{
"type": "library",
"bom-ref": "pkg:maven/compiler/compiler@23.1.4.0-1-redhat-00001?type=jar",
"name": "compiler",
"version": "23.1.4.0-1-redhat-00001",
"purl": "pkg:maven/compiler/compiler@23.1.4.0-1-redhat-00001?type=jar",
"externalReferences": [
{
"type": "build-meta",
"url": "",
"hashes": [
{
"alg": "SHA-1",
"content": "e96edb6e7bab65204479c293378a7485ae2d1c8f"
}
]
}
],
"properties": [
{
"name": "sbomer:package:language",
"value": "java"
},
{
"name": "sbomer:package:type",
"value": "java-archive"
},
{
"name": "sbomer:location:0:path",
"value": "/usr/share/java/quarkus-mandrel-java/compiler.jar"
}
]
}
]
}
],
"dependencies": [
{
"ref": "pkg:oci/mandrel-for-jdk-21-rhel8@sha256%3A41d92dafa5ccbf7f76fa81c5a0e7de83c51166f27bea9b98df018f644016bf04?arch=amd64&os=linux&tag=23.1-13.1724180416",
"dependsOn": [
"pkg:rpm/redhat/abattis-cantarell-fonts@0.0.25-6.el8?arch=noarch",
"pkg:maven/compiler/compiler@23.1.4.0-1-redhat-00001?type=jar"
]
},
{
"ref": "pkg:rpm/redhat/abattis-cantarell-fonts@0.0.25-6.el8?arch=noarch",
"dependsOn": []
},
{
"ref": "pkg:maven/compiler/compiler@23.1.4.0-1-redhat-00001?type=jar",
"dependsOn": []
}
]
}
134 changes: 132 additions & 2 deletions internal/testing/testdata/testdata.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package testdata
import (
_ "embed"
"encoding/base64"
"strings"
"time"

"github.com/google/go-cmp/cmp"
Expand Down Expand Up @@ -194,6 +195,12 @@ var (
//go:embed exampledata/small-legal-cyclonedx.json
CycloneDXLegalExample []byte

//go:embed exampledata/cyclonedx-components-nested.json
CycloneDXComponentsNested []byte

//go:embed exampledata/cyclonedx-components-flat.json
CycloneDXComponentsFlat []byte

// json format
json = jsoniter.ConfigCompatibleWithStandardLibrary
// CycloneDX VEX testdata unaffected
Expand Down Expand Up @@ -1625,6 +1632,123 @@ var (
CertifyLegal: quarkusParentPackageLegal,
}

NestedComponentsPredicates = assembler.IngestPredicates{
IsDependency: ociComponentsIsDependencyIngests,
IsOccurrence: []assembler.IsOccurrenceIngest{
{
Pkg: ociMandrel,
Artifact: ociMandrelArtifact,
IsOccurrence: isOccurrenceJustifyTopPkg,
},
},
HasSBOM: nestedComponentsHasSBOM,
}

FlatComponentsPredicates = assembler.IngestPredicates{
IsDependency: ociComponentsIsDependencyIngests,
IsOccurrence: []assembler.IsOccurrenceIngest{
{
Pkg: ociMandrel,
Artifact: ociMandrelArtifact,
IsOccurrence: isOccurrenceJustifyTopPkg,
},
},
HasSBOM: flatComponentsHasSBOM,
}

ociComponentsIsDependencyIngests = []assembler.IsDependencyIngest{
{
Pkg: ociMandrel,
DepPkg: mavenCompiler,
IsDependency: &model.IsDependencyInputSpec{
DependencyType: model.DependencyTypeDirect,
Justification: isCDXDepJustifyDependsJustification,
},
},
{
Pkg: ociMandrel,
DepPkg: mavenCompiler,
IsDependency: &model.IsDependencyInputSpec{
DependencyType: model.DependencyTypeUnknown,
Justification: isDepJustifyTopPkgJustification,
},
},
{
Pkg: ociMandrel,
DepPkg: mavenCompiler,
IsDependency: &model.IsDependencyInputSpec{
DependencyType: model.DependencyTypeUnknown,
Justification: isDepJustifyTopPkgJustification,
},
},
{
Pkg: ociMandrel,
DepPkg: ociMandrel,
IsDependency: &model.IsDependencyInputSpec{
DependencyType: model.DependencyTypeUnknown,
Justification: isDepJustifyTopPkgJustification,
},
},
{
Pkg: ociMandrel,
DepPkg: abattisCantarellFonts,
IsDependency: &model.IsDependencyInputSpec{
DependencyType: model.DependencyTypeDirect,
Justification: isCDXDepJustifyDependsJustification,
},
},
{
Pkg: ociMandrel,
DepPkg: abattisCantarellFonts,
IsDependency: &model.IsDependencyInputSpec{
DependencyType: model.DependencyTypeUnknown,
Justification: isDepJustifyTopPkgJustification,
},
},
{
Pkg: ociMandrel,
DepPkg: abattisCantarellFonts,
IsDependency: &model.IsDependencyInputSpec{
DependencyType: model.DependencyTypeUnknown,
Justification: isDepJustifyTopPkgJustification,
},
},
}

ociMandrel, _ = asmhelpers.PurlToPkg("pkg:oci/mandrel-for-jdk-21-rhel8@sha256%3A41d92dafa5ccbf7f76fa81c5a0e7de83c51166f27bea9b98df018f644016bf04?arch=amd64&os=linux&tag=23.1-13.1724180416")
mavenCompiler, _ = asmhelpers.PurlToPkg("pkg:maven/compiler/compiler@23.1.4.0-1-redhat-00001?type=jar")
abattisCantarellFonts, _ = asmhelpers.PurlToPkg("pkg:rpm/redhat/abattis-cantarell-fonts@0.0.25-6.el8?arch=noarch")
ociMandrelArtifact = &model.ArtifactInputSpec{
Algorithm: "sha256",
Digest: "41d92dafa5ccbf7f76fa81c5a0e7de83c51166f27bea9b98df018f644016bf04",
}

nestedComponentsHasSBOM = []assembler.HasSBOMIngest{
{
Artifact: ociMandrelArtifact,
HasSBOM: &model.HasSBOMInputSpec{
Uri: "urn:uuid:c096003c-c9fa-4d9e-9390-fefa51745fe1",
Algorithm: "sha256",
Digest: "6a9598f69e87d0c45f3dd4c5d69d8812b734b28f07506a9f7b6ada7e9696c5e5",
KnownSince: nestedComponentsTime,
},
},
}

flatComponentsHasSBOM = []assembler.HasSBOMIngest{
{
Artifact: ociMandrelArtifact,
HasSBOM: &model.HasSBOMInputSpec{
Uri: "urn:uuid:c096003c-c9fa-4d9e-9390-fefa51745fe1",
Algorithm: "sha256",
Digest: "1dedfbd09dbf68a29279395444e76f300285cf1731ad25f39252c4d689403531",
KnownSince: nestedComponentsTime,
},
},
}

nestedComponentsTime, _ = time.Parse(time.RFC3339, "2024-09-24T08:20:03Z")

// ceritifer testdata

Text4ShellVulAttestation = `{
Expand Down Expand Up @@ -3341,8 +3465,14 @@ func certifyScorecardLess(e1, e2 assembler.CertifyScorecardIngest) bool {
return gLess(e1, e2)
}

func isDependencyLess(e1, e2 assembler.IsDependencyIngest) bool {
return gLess(e1, e2)
func isDependencyLess(a, b assembler.IsDependencyIngest) bool {
if strings.Compare(a.Pkg.Name, b.Pkg.Name) != 0 {
return a.Pkg.Name < b.Pkg.Name
}
if d := strings.Compare(a.DepPkg.Name, b.DepPkg.Name); d != 0 {
return a.DepPkg.Name < b.DepPkg.Name
}
return false
}

func isOccurenceLess(e1, e2 assembler.IsOccurrenceIngest) bool {
Expand Down
12 changes: 10 additions & 2 deletions pkg/ingestor/parser/cyclonedx/parser_cyclonedx.go
Original file line number Diff line number Diff line change
Expand Up @@ -210,8 +210,12 @@ func parseContainerType(name string, version string, topLevel bool) string {
}

func (c *cyclonedxParser) getPackages() error {
if c.cdxBom.Components != nil {
for _, comp := range *c.cdxBom.Components {
return traverseComponents(*c, c.cdxBom.Components)
}

func traverseComponents(c cyclonedxParser, components *[]cdx.Component) error {
if components != nil {
for _, comp := range *components {
// skipping over the "operating-system" type as it does not contain
// the required purl for package node. Currently there is no use-case
// to capture OS for GUAC.
Expand Down Expand Up @@ -250,6 +254,10 @@ func (c *cyclonedxParser) getPackages() error {
if err := c.getLicenseInformation(comp); err != nil {
return fmt.Errorf("failed to get license information for component package with error: %w", err)
}

if err := traverseComponents(c, comp.Components); err != nil {
return err
}
}
}
return nil
Expand Down
Loading

0 comments on commit 8cbb091

Please sign in to comment.