Skip to content

Commit efb1f69

Browse files
authored
feat(sbom): add vulnerability support for SPDX formats (#7213)
1 parent 0e286f0 commit efb1f69

File tree

3 files changed

+126
-7
lines changed

3 files changed

+126
-7
lines changed

pkg/flag/options.go

+2-7
Original file line numberDiff line numberDiff line change
@@ -410,15 +410,10 @@ func (o *Options) enableSBOM() {
410410
o.Scanners.Enable(types.SBOMScanner)
411411
}
412412

413-
if o.Format == types.FormatSPDX || o.Format == types.FormatSPDXJSON {
414-
log.Info(`"--format spdx" and "--format spdx-json" disable security scanning`)
415-
o.Scanners = types.Scanners{types.SBOMScanner}
416-
}
417-
418-
if o.Format == types.FormatCycloneDX {
413+
if o.Format == types.FormatCycloneDX || o.Format == types.FormatSPDX || o.Format == types.FormatSPDXJSON {
419414
// Vulnerability scanning is disabled by default for CycloneDX.
420415
if !viper.IsSet(ScannersFlag.ConfigName) {
421-
log.Info(`"--format cyclonedx" disables security scanning. Specify "--scanners vuln" explicitly if you want to include vulnerabilities in the CycloneDX report.`)
416+
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))
422417
o.Scanners = nil
423418
}
424419
o.Scanners.Enable(types.SBOMScanner)

pkg/sbom/spdx/marshal.go

+18
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,15 @@ func (m *Marshaler) Marshal(ctx context.Context, bom *core.BOM) (*spdx.Document,
147147
if err != nil {
148148
return nil, xerrors.Errorf("spdx package error: %w", err)
149149
}
150+
151+
// Add advisories for package
152+
// cf. https://spdx.github.io/spdx-spec/v2.3/how-to-use/#k1-including-security-information-in-a-spdx-document
153+
if vulns, ok := bom.Vulnerabilities()[c.ID()]; ok {
154+
for _, v := range vulns {
155+
spdxPackage.PackageExternalReferences = append(spdxPackage.PackageExternalReferences, m.advisoryExternalReference(v.PrimaryURL))
156+
}
157+
}
158+
150159
packages = append(packages, &spdxPackage)
151160
packageIDs[c.ID()] = spdxPackage.PackageSPDXIdentifier
152161

@@ -184,6 +193,7 @@ func (m *Marshaler) Marshal(ctx context.Context, bom *core.BOM) (*spdx.Document,
184193
relationShips = append(relationShips, m.spdxRelationShip(refA, refB, m.spdxRelationshipType(rel.Type)))
185194
}
186195
}
196+
187197
sortPackages(packages)
188198
sortRelationships(relationShips)
189199
sortFiles(files)
@@ -268,6 +278,14 @@ func (m *Marshaler) purlExternalReference(packageURL string) *spdx.PackageExtern
268278
}
269279
}
270280

281+
func (m *Marshaler) advisoryExternalReference(primaryURL string) *spdx.PackageExternalReference {
282+
return &spdx.PackageExternalReference{
283+
Category: common.CategorySecurity,
284+
RefType: common.TypeSecurityAdvisory,
285+
Locator: primaryURL,
286+
}
287+
}
288+
271289
func (m *Marshaler) spdxPackage(c *core.Component, pkgDownloadLocation string) (spdx.Package, error) {
272290
pkgID, err := calcPkgID(m.hasher, c)
273291
if err != nil {

pkg/sbom/spdx/marshal_test.go

+106
Original file line numberDiff line numberDiff line change
@@ -821,6 +821,112 @@ func TestMarshaler_Marshal(t *testing.T) {
821821
},
822822
},
823823
},
824+
{
825+
name: "happy path with vulnerability",
826+
inputReport: types.Report{
827+
SchemaVersion: report.SchemaVersion,
828+
ArtifactName: "log4j-core-2.17.0.jar",
829+
ArtifactType: artifact.TypeFilesystem,
830+
Results: types.Results{
831+
{
832+
Target: "Java",
833+
Class: types.ClassLangPkg,
834+
Type: ftypes.Jar,
835+
Packages: []ftypes.Package{
836+
{
837+
Name: "org.apache.logging.log4j:log4j-core",
838+
Version: "2.17.0",
839+
Identifier: ftypes.PkgIdentifier{
840+
PURL: &packageurl.PackageURL{
841+
Type: packageurl.TypeMaven,
842+
Namespace: "org.apache.logging.log4j",
843+
Name: "log4j-core",
844+
Version: "2.17.0",
845+
},
846+
},
847+
},
848+
},
849+
Vulnerabilities: []types.DetectedVulnerability{
850+
{
851+
VulnerabilityID: "CVE-2021-44832",
852+
PkgName: "org.apache.logging.log4j:log4j-core",
853+
InstalledVersion: "2.17.0",
854+
FixedVersion: "2.3.2, 2.12.4, 2.17.1",
855+
PrimaryURL: "https://avd.aquasec.com/nvd/cve-2021-44832",
856+
},
857+
},
858+
},
859+
},
860+
},
861+
wantSBOM: &spdx.Document{
862+
SPDXVersion: spdx.Version,
863+
DataLicense: spdx.DataLicense,
864+
SPDXIdentifier: "DOCUMENT",
865+
DocumentName: "log4j-core-2.17.0.jar",
866+
DocumentNamespace: "http://aquasecurity.github.io/trivy/filesystem/log4j-core-2.17.0.jar-3ff14136-e09f-4df9-80ea-000000000003",
867+
CreationInfo: &spdx.CreationInfo{
868+
Creators: []common.Creator{
869+
{
870+
Creator: "aquasecurity",
871+
CreatorType: "Organization",
872+
},
873+
{
874+
Creator: "trivy-0.38.1",
875+
CreatorType: "Tool",
876+
},
877+
},
878+
Created: "2021-08-25T12:20:30Z",
879+
},
880+
Packages: []*spdx.Package{
881+
{
882+
PackageSPDXIdentifier: spdx.ElementID("Package-4ee6f197f4811213"),
883+
PackageDownloadLocation: "NONE",
884+
PackageName: "org.apache.logging.log4j:log4j-core",
885+
PackageVersion: "2.17.0",
886+
PackageLicenseConcluded: "NONE",
887+
PackageLicenseDeclared: "NONE",
888+
PackageExternalReferences: []*spdx.PackageExternalReference{
889+
{
890+
Category: tspdx.CategoryPackageManager,
891+
RefType: tspdx.RefTypePurl,
892+
Locator: "pkg:maven/org.apache.logging.log4j/[email protected]",
893+
},
894+
{
895+
Category: "SECURITY",
896+
RefType: "advisory",
897+
Locator: "https://avd.aquasec.com/nvd/cve-2021-44832",
898+
},
899+
},
900+
PrimaryPackagePurpose: tspdx.PackagePurposeLibrary,
901+
PackageSupplier: &spdx.Supplier{Supplier: tspdx.PackageSupplierNoAssertion},
902+
PackageAttributionTexts: []string{
903+
"PkgType: jar",
904+
},
905+
},
906+
{
907+
PackageSPDXIdentifier: spdx.ElementID("Filesystem-121e7e7a43f02ab"),
908+
PackageDownloadLocation: "NONE",
909+
PackageName: "log4j-core-2.17.0.jar",
910+
PackageAttributionTexts: []string{
911+
"SchemaVersion: 2",
912+
},
913+
PrimaryPackagePurpose: tspdx.PackagePurposeSource,
914+
},
915+
},
916+
Relationships: []*spdx.Relationship{
917+
{
918+
RefA: spdx.DocElementID{ElementRefID: "DOCUMENT"},
919+
RefB: spdx.DocElementID{ElementRefID: "Filesystem-121e7e7a43f02ab"},
920+
Relationship: "DESCRIBES",
921+
},
922+
{
923+
RefA: spdx.DocElementID{ElementRefID: "Filesystem-121e7e7a43f02ab"},
924+
RefB: spdx.DocElementID{ElementRefID: "Package-4ee6f197f4811213"},
925+
Relationship: "CONTAINS",
926+
},
927+
},
928+
},
929+
},
824930
{
825931
name: "happy path aggregate results",
826932
inputReport: types.Report{

0 commit comments

Comments
 (0)