Skip to content

Commit f2bb9c6

Browse files
authored
fix(sbom): use Annotation instead of AttributionTexts for SPDX formats (aquasecurity#7811)
1 parent b661d68 commit f2bb9c6

File tree

6 files changed

+316
-158
lines changed

6 files changed

+316
-158
lines changed

integration/testdata/conda-spdx.json.golden

+27-12
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,15 @@
3131
"referenceLocator": "pkg:conda/[email protected]"
3232
}
3333
],
34-
"attributionTexts": [
35-
"PkgType: conda-pkg"
36-
],
37-
"primaryPackagePurpose": "LIBRARY"
34+
"primaryPackagePurpose": "LIBRARY",
35+
"annotations": [
36+
{
37+
"annotator": "Tool: trivy-dev",
38+
"annotationDate": "2021-08-25T12:20:30Z",
39+
"annotationType": "OTHER",
40+
"comment": "PkgType: conda-pkg"
41+
}
42+
]
3843
},
3944
{
4045
"name": "pip",
@@ -55,20 +60,30 @@
5560
"referenceLocator": "pkg:conda/[email protected]"
5661
}
5762
],
58-
"attributionTexts": [
59-
"PkgType: conda-pkg"
60-
],
61-
"primaryPackagePurpose": "LIBRARY"
63+
"primaryPackagePurpose": "LIBRARY",
64+
"annotations": [
65+
{
66+
"annotator": "Tool: trivy-dev",
67+
"annotationDate": "2021-08-25T12:20:30Z",
68+
"annotationType": "OTHER",
69+
"comment": "PkgType: conda-pkg"
70+
}
71+
]
6272
},
6373
{
6474
"name": "testdata/fixtures/repo/conda",
6575
"SPDXID": "SPDXRef-Filesystem-2e2426fd0f2580ef",
6676
"downloadLocation": "NONE",
6777
"filesAnalyzed": false,
68-
"attributionTexts": [
69-
"SchemaVersion: 2"
70-
],
71-
"primaryPackagePurpose": "SOURCE"
78+
"primaryPackagePurpose": "SOURCE",
79+
"annotations": [
80+
{
81+
"annotator": "Tool: trivy-dev",
82+
"annotationDate": "2021-08-25T12:20:30Z",
83+
"annotationType": "OTHER",
84+
"comment": "SchemaVersion: 2"
85+
}
86+
]
7287
}
7388
],
7489
"files": [

integration/testdata/julia-spdx.json.golden

+69-24
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,21 @@
1717
"SPDXID": "SPDXRef-Application-18fc3597717a3e56",
1818
"downloadLocation": "NONE",
1919
"filesAnalyzed": false,
20-
"attributionTexts": [
21-
"Class: lang-pkgs",
22-
"Type: julia"
23-
],
24-
"primaryPackagePurpose": "APPLICATION"
20+
"primaryPackagePurpose": "APPLICATION",
21+
"annotations": [
22+
{
23+
"annotator": "Tool: trivy-dev",
24+
"annotationDate": "2021-08-25T12:20:30Z",
25+
"annotationType": "OTHER",
26+
"comment": "Class: lang-pkgs"
27+
},
28+
{
29+
"annotator": "Tool: trivy-dev",
30+
"annotationDate": "2021-08-25T12:20:30Z",
31+
"annotationType": "OTHER",
32+
"comment": "Type: julia"
33+
}
34+
]
2535
},
2636
{
2737
"name": "A",
@@ -40,11 +50,21 @@
4050
"referenceLocator": "pkg:julia/[email protected]?uuid=ead4f63c-334e-11e9-00e6-e7f0a5f21b60"
4151
}
4252
],
43-
"attributionTexts": [
44-
"PkgID: ead4f63c-334e-11e9-00e6-e7f0a5f21b60",
45-
"PkgType: julia"
46-
],
47-
"primaryPackagePurpose": "LIBRARY"
53+
"primaryPackagePurpose": "LIBRARY",
54+
"annotations": [
55+
{
56+
"annotator": "Tool: trivy-dev",
57+
"annotationDate": "2021-08-25T12:20:30Z",
58+
"annotationType": "OTHER",
59+
"comment": "PkgID: ead4f63c-334e-11e9-00e6-e7f0a5f21b60"
60+
},
61+
{
62+
"annotator": "Tool: trivy-dev",
63+
"annotationDate": "2021-08-25T12:20:30Z",
64+
"annotationType": "OTHER",
65+
"comment": "PkgType: julia"
66+
}
67+
]
4868
},
4969
{
5070
"name": "B",
@@ -63,11 +83,21 @@
6383
"referenceLocator": "pkg:julia/[email protected]?uuid=f41f7b98-334e-11e9-1257-49272045fb24"
6484
}
6585
],
66-
"attributionTexts": [
67-
"PkgID: f41f7b98-334e-11e9-1257-49272045fb24",
68-
"PkgType: julia"
69-
],
70-
"primaryPackagePurpose": "LIBRARY"
86+
"primaryPackagePurpose": "LIBRARY",
87+
"annotations": [
88+
{
89+
"annotator": "Tool: trivy-dev",
90+
"annotationDate": "2021-08-25T12:20:30Z",
91+
"annotationType": "OTHER",
92+
"comment": "PkgID: f41f7b98-334e-11e9-1257-49272045fb24"
93+
},
94+
{
95+
"annotator": "Tool: trivy-dev",
96+
"annotationDate": "2021-08-25T12:20:30Z",
97+
"annotationType": "OTHER",
98+
"comment": "PkgType: julia"
99+
}
100+
]
71101
},
72102
{
73103
"name": "B",
@@ -86,21 +116,36 @@
86116
"referenceLocator": "pkg:julia/[email protected]?uuid=edca9bc6-334e-11e9-3554-9595dbb4349c"
87117
}
88118
],
89-
"attributionTexts": [
90-
"PkgID: edca9bc6-334e-11e9-3554-9595dbb4349c",
91-
"PkgType: julia"
92-
],
93-
"primaryPackagePurpose": "LIBRARY"
119+
"primaryPackagePurpose": "LIBRARY",
120+
"annotations": [
121+
{
122+
"annotator": "Tool: trivy-dev",
123+
"annotationDate": "2021-08-25T12:20:30Z",
124+
"annotationType": "OTHER",
125+
"comment": "PkgID: edca9bc6-334e-11e9-3554-9595dbb4349c"
126+
},
127+
{
128+
"annotator": "Tool: trivy-dev",
129+
"annotationDate": "2021-08-25T12:20:30Z",
130+
"annotationType": "OTHER",
131+
"comment": "PkgType: julia"
132+
}
133+
]
94134
},
95135
{
96136
"name": "testdata/fixtures/repo/julia",
97137
"SPDXID": "SPDXRef-Filesystem-1be792dd0077c431",
98138
"downloadLocation": "NONE",
99139
"filesAnalyzed": false,
100-
"attributionTexts": [
101-
"SchemaVersion: 2"
102-
],
103-
"primaryPackagePurpose": "SOURCE"
140+
"primaryPackagePurpose": "SOURCE",
141+
"annotations": [
142+
{
143+
"annotator": "Tool: trivy-dev",
144+
"annotationDate": "2021-08-25T12:20:30Z",
145+
"annotationType": "OTHER",
146+
"comment": "SchemaVersion: 2"
147+
}
148+
]
104149
}
105150
],
106151
"relationships": [

pkg/sbom/spdx/marshal.go

+27-15
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ const (
5050
PackageSupplierNoAssertion = "NOASSERTION"
5151
PackageSupplierOrganization = "Organization"
5252

53+
PackageAnnotatorToolField = "Tool"
54+
5355
RelationShipContains = common.TypeRelationshipContains
5456
RelationShipDescribe = common.TypeRelationshipDescribe
5557
RelationShipDependsOn = common.TypeRelationshipDependsOn
@@ -122,14 +124,17 @@ func (m *Marshaler) Marshal(ctx context.Context, bom *core.BOM) (*spdx.Document,
122124
packages []*spdx.Package
123125
)
124126

127+
// Lock time to use same time for all spdx fields
128+
timeNow := clock.Now(ctx).UTC().Format(time.RFC3339)
129+
125130
root := bom.Root()
126131
pkgDownloadLocation := m.packageDownloadLocation(root)
127132

128133
// Component ID => SPDX ID
129134
packageIDs := make(map[uuid.UUID]spdx.ElementID)
130135

131136
// Root package contains OS, OS packages, language-specific packages and so on.
132-
rootPkg, err := m.rootSPDXPackage(root, pkgDownloadLocation)
137+
rootPkg, err := m.rootSPDXPackage(root, timeNow, pkgDownloadLocation)
133138
if err != nil {
134139
return nil, xerrors.Errorf("failed to generate a root package: %w", err)
135140
}
@@ -144,7 +149,7 @@ func (m *Marshaler) Marshal(ctx context.Context, bom *core.BOM) (*spdx.Document,
144149
if c.Root {
145150
continue
146151
}
147-
spdxPackage, err := m.spdxPackage(c, pkgDownloadLocation)
152+
spdxPackage, err := m.spdxPackage(c, timeNow, pkgDownloadLocation)
148153
if err != nil {
149154
return nil, xerrors.Errorf("spdx package error: %w", err)
150155
}
@@ -216,7 +221,7 @@ func (m *Marshaler) Marshal(ctx context.Context, bom *core.BOM) (*spdx.Document,
216221
CreatorType: "Tool",
217222
},
218223
},
219-
Created: clock.Now(ctx).UTC().Format(time.RFC3339),
224+
Created: timeNow,
220225
},
221226
Packages: packages,
222227
Relationships: relationShips,
@@ -237,7 +242,7 @@ func (m *Marshaler) packageDownloadLocation(root *core.Component) string {
237242
return location
238243
}
239244

240-
func (m *Marshaler) rootSPDXPackage(root *core.Component, pkgDownloadLocation string) (*spdx.Package, error) {
245+
func (m *Marshaler) rootSPDXPackage(root *core.Component, timeNow, pkgDownloadLocation string) (*spdx.Package, error) {
241246
var externalReferences []*spdx.PackageExternalReference
242247
// When the target is a container image, add PURL to the external references of the root package.
243248
if root.PkgIdentifier.PURL != nil {
@@ -258,17 +263,25 @@ func (m *Marshaler) rootSPDXPackage(root *core.Component, pkgDownloadLocation st
258263
PackageName: root.Name,
259264
PackageSPDXIdentifier: elementID(camelCase(string(root.Type)), pkgID),
260265
PackageDownloadLocation: pkgDownloadLocation,
261-
PackageAttributionTexts: m.spdxAttributionTexts(root),
266+
Annotations: m.spdxAnnotations(root, timeNow),
262267
PackageExternalReferences: externalReferences,
263268
PrimaryPackagePurpose: pkgPurpose,
264269
}, nil
265270
}
266271

267-
func (m *Marshaler) appendAttributionText(attributionTexts []string, key, value string) []string {
272+
func (m *Marshaler) appendAnnotation(annotations []spdx.Annotation, timeNow, key, value string) []spdx.Annotation {
268273
if value == "" {
269-
return attributionTexts
274+
return annotations
270275
}
271-
return append(attributionTexts, fmt.Sprintf("%s: %s", key, value))
276+
return append(annotations, spdx.Annotation{
277+
AnnotationDate: timeNow,
278+
AnnotationType: spdx.CategoryOther,
279+
Annotator: spdx.Annotator{
280+
Annotator: fmt.Sprintf("%s-%s", CreatorTool, m.appVersion),
281+
AnnotatorType: PackageAnnotatorToolField,
282+
},
283+
AnnotationComment: fmt.Sprintf("%s: %s", key, value),
284+
})
272285
}
273286

274287
func (m *Marshaler) purlExternalReference(packageURL string) *spdx.PackageExternalReference {
@@ -287,7 +300,7 @@ func (m *Marshaler) advisoryExternalReference(primaryURL string) *spdx.PackageEx
287300
}
288301
}
289302

290-
func (m *Marshaler) spdxPackage(c *core.Component, pkgDownloadLocation string) (spdx.Package, error) {
303+
func (m *Marshaler) spdxPackage(c *core.Component, timeNow, pkgDownloadLocation string) (spdx.Package, error) {
291304
pkgID, err := calcPkgID(m.hasher, c)
292305
if err != nil {
293306
return spdx.Package{}, xerrors.Errorf("failed to get os metadata package ID: %w", err)
@@ -343,7 +356,7 @@ func (m *Marshaler) spdxPackage(c *core.Component, pkgDownloadLocation string) (
343356
PrimaryPackagePurpose: purpose,
344357
PackageDownloadLocation: pkgDownloadLocation,
345358
PackageExternalReferences: pkgExtRefs,
346-
PackageAttributionTexts: m.spdxAttributionTexts(c),
359+
Annotations: m.spdxAnnotations(c, timeNow),
347360
PackageSourceInfo: sourceInfo,
348361
PackageSupplier: supplier,
349362
PackageChecksums: m.spdxChecksums(digests),
@@ -365,16 +378,15 @@ func spdxPkgName(component *core.Component) string {
365378
}
366379
return component.Name
367380
}
368-
369-
func (m *Marshaler) spdxAttributionTexts(c *core.Component) []string {
370-
var texts []string
381+
func (m *Marshaler) spdxAnnotations(c *core.Component, timeNow string) []spdx.Annotation {
382+
var annotations []spdx.Annotation
371383
for _, p := range c.Properties {
372384
// Add properties that are not in other fields.
373385
if !slices.Contains(duplicateProperties, p.Name) {
374-
texts = m.appendAttributionText(texts, p.Name, p.Value)
386+
annotations = m.appendAnnotation(annotations, timeNow, p.Name, p.Value)
375387
}
376388
}
377-
return texts
389+
return annotations
378390
}
379391

380392
func (m *Marshaler) spdxLicense(c *core.Component) string {

0 commit comments

Comments
 (0)