Skip to content

Commit

Permalink
feat(sbom): add vulnerability support for SPDX formats (#7213)
Browse files Browse the repository at this point in the history
  • Loading branch information
DmitriyLewen authored Jul 25, 2024
1 parent 0e286f0 commit efb1f69
Show file tree
Hide file tree
Showing 3 changed files with 126 additions and 7 deletions.
9 changes: 2 additions & 7 deletions pkg/flag/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -410,15 +410,10 @@ func (o *Options) enableSBOM() {
o.Scanners.Enable(types.SBOMScanner)
}

if o.Format == types.FormatSPDX || o.Format == types.FormatSPDXJSON {
log.Info(`"--format spdx" and "--format spdx-json" disable security scanning`)
o.Scanners = types.Scanners{types.SBOMScanner}
}

if o.Format == types.FormatCycloneDX {
if o.Format == types.FormatCycloneDX || o.Format == types.FormatSPDX || o.Format == types.FormatSPDXJSON {
// Vulnerability scanning is disabled by default for CycloneDX.
if !viper.IsSet(ScannersFlag.ConfigName) {
log.Info(`"--format cyclonedx" disables security scanning. Specify "--scanners vuln" explicitly if you want to include vulnerabilities in the CycloneDX report.`)
log.Info(fmt.Sprintf(`"--format %[1]s" disables security scanning. Specify "--scanners vuln" explicitly if you want to include vulnerabilities in the "%[1]s" report.`, o.Format))
o.Scanners = nil
}
o.Scanners.Enable(types.SBOMScanner)
Expand Down
18 changes: 18 additions & 0 deletions pkg/sbom/spdx/marshal.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,15 @@ func (m *Marshaler) Marshal(ctx context.Context, bom *core.BOM) (*spdx.Document,
if err != nil {
return nil, xerrors.Errorf("spdx package error: %w", err)
}

// Add advisories for package
// cf. https://spdx.github.io/spdx-spec/v2.3/how-to-use/#k1-including-security-information-in-a-spdx-document
if vulns, ok := bom.Vulnerabilities()[c.ID()]; ok {
for _, v := range vulns {
spdxPackage.PackageExternalReferences = append(spdxPackage.PackageExternalReferences, m.advisoryExternalReference(v.PrimaryURL))
}
}

packages = append(packages, &spdxPackage)
packageIDs[c.ID()] = spdxPackage.PackageSPDXIdentifier

Expand Down Expand Up @@ -184,6 +193,7 @@ func (m *Marshaler) Marshal(ctx context.Context, bom *core.BOM) (*spdx.Document,
relationShips = append(relationShips, m.spdxRelationShip(refA, refB, m.spdxRelationshipType(rel.Type)))
}
}

sortPackages(packages)
sortRelationships(relationShips)
sortFiles(files)
Expand Down Expand Up @@ -268,6 +278,14 @@ func (m *Marshaler) purlExternalReference(packageURL string) *spdx.PackageExtern
}
}

func (m *Marshaler) advisoryExternalReference(primaryURL string) *spdx.PackageExternalReference {
return &spdx.PackageExternalReference{
Category: common.CategorySecurity,
RefType: common.TypeSecurityAdvisory,
Locator: primaryURL,
}
}

func (m *Marshaler) spdxPackage(c *core.Component, pkgDownloadLocation string) (spdx.Package, error) {
pkgID, err := calcPkgID(m.hasher, c)
if err != nil {
Expand Down
106 changes: 106 additions & 0 deletions pkg/sbom/spdx/marshal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -821,6 +821,112 @@ func TestMarshaler_Marshal(t *testing.T) {
},
},
},
{
name: "happy path with vulnerability",
inputReport: types.Report{
SchemaVersion: report.SchemaVersion,
ArtifactName: "log4j-core-2.17.0.jar",
ArtifactType: artifact.TypeFilesystem,
Results: types.Results{
{
Target: "Java",
Class: types.ClassLangPkg,
Type: ftypes.Jar,
Packages: []ftypes.Package{
{
Name: "org.apache.logging.log4j:log4j-core",
Version: "2.17.0",
Identifier: ftypes.PkgIdentifier{
PURL: &packageurl.PackageURL{
Type: packageurl.TypeMaven,
Namespace: "org.apache.logging.log4j",
Name: "log4j-core",
Version: "2.17.0",
},
},
},
},
Vulnerabilities: []types.DetectedVulnerability{
{
VulnerabilityID: "CVE-2021-44832",
PkgName: "org.apache.logging.log4j:log4j-core",
InstalledVersion: "2.17.0",
FixedVersion: "2.3.2, 2.12.4, 2.17.1",
PrimaryURL: "https://avd.aquasec.com/nvd/cve-2021-44832",
},
},
},
},
},
wantSBOM: &spdx.Document{
SPDXVersion: spdx.Version,
DataLicense: spdx.DataLicense,
SPDXIdentifier: "DOCUMENT",
DocumentName: "log4j-core-2.17.0.jar",
DocumentNamespace: "http://aquasecurity.github.io/trivy/filesystem/log4j-core-2.17.0.jar-3ff14136-e09f-4df9-80ea-000000000003",
CreationInfo: &spdx.CreationInfo{
Creators: []common.Creator{
{
Creator: "aquasecurity",
CreatorType: "Organization",
},
{
Creator: "trivy-0.38.1",
CreatorType: "Tool",
},
},
Created: "2021-08-25T12:20:30Z",
},
Packages: []*spdx.Package{
{
PackageSPDXIdentifier: spdx.ElementID("Package-4ee6f197f4811213"),
PackageDownloadLocation: "NONE",
PackageName: "org.apache.logging.log4j:log4j-core",
PackageVersion: "2.17.0",
PackageLicenseConcluded: "NONE",
PackageLicenseDeclared: "NONE",
PackageExternalReferences: []*spdx.PackageExternalReference{
{
Category: tspdx.CategoryPackageManager,
RefType: tspdx.RefTypePurl,
Locator: "pkg:maven/org.apache.logging.log4j/[email protected]",
},
{
Category: "SECURITY",
RefType: "advisory",
Locator: "https://avd.aquasec.com/nvd/cve-2021-44832",
},
},
PrimaryPackagePurpose: tspdx.PackagePurposeLibrary,
PackageSupplier: &spdx.Supplier{Supplier: tspdx.PackageSupplierNoAssertion},
PackageAttributionTexts: []string{
"PkgType: jar",
},
},
{
PackageSPDXIdentifier: spdx.ElementID("Filesystem-121e7e7a43f02ab"),
PackageDownloadLocation: "NONE",
PackageName: "log4j-core-2.17.0.jar",
PackageAttributionTexts: []string{
"SchemaVersion: 2",
},
PrimaryPackagePurpose: tspdx.PackagePurposeSource,
},
},
Relationships: []*spdx.Relationship{
{
RefA: spdx.DocElementID{ElementRefID: "DOCUMENT"},
RefB: spdx.DocElementID{ElementRefID: "Filesystem-121e7e7a43f02ab"},
Relationship: "DESCRIBES",
},
{
RefA: spdx.DocElementID{ElementRefID: "Filesystem-121e7e7a43f02ab"},
RefB: spdx.DocElementID{ElementRefID: "Package-4ee6f197f4811213"},
Relationship: "CONTAINS",
},
},
},
},
{
name: "happy path aggregate results",
inputReport: types.Report{
Expand Down

0 comments on commit efb1f69

Please sign in to comment.