@@ -50,6 +50,7 @@ func (b *BOM) convert(specVersion SpecVersion) {
50
50
}
51
51
if specVersion < SpecVersion1_5 {
52
52
b .Annotations = nil
53
+ b .Formulation = nil
53
54
}
54
55
55
56
if b .Metadata != nil {
@@ -61,13 +62,13 @@ func (b *BOM) convert(specVersion SpecVersion) {
61
62
b .Metadata .Lifecycles = nil
62
63
}
63
64
65
+ if specVersion < SpecVersion1_5 {
66
+ b .Metadata .Lifecycles = nil
67
+ }
68
+
64
69
recurseComponent (b .Metadata .Component , componentConverter (specVersion ))
65
70
convertLicenses (b .Metadata .Licenses , specVersion )
66
- if b .Metadata .Tools != nil {
67
- for i := range * b .Metadata .Tools {
68
- convertTool (& (* b .Metadata .Tools )[i ], specVersion )
69
- }
70
- }
71
+ convertTools (b .Metadata .Tools , specVersion )
71
72
}
72
73
73
74
if b .Components != nil {
@@ -82,6 +83,18 @@ func (b *BOM) convert(specVersion SpecVersion) {
82
83
}
83
84
}
84
85
86
+ if b .Vulnerabilities != nil {
87
+ convertVulnerabilities (b .Vulnerabilities , specVersion )
88
+ }
89
+
90
+ if b .Compositions != nil {
91
+ convertCompositions (b .Compositions , specVersion )
92
+ }
93
+
94
+ if b .ExternalReferences != nil {
95
+ convertExternalReferences (b .ExternalReferences , specVersion )
96
+ }
97
+
85
98
b .SpecVersion = specVersion
86
99
b .XMLNS = xmlNamespaces [specVersion ]
87
100
b .JSONSchema = jsonSchemas [specVersion ]
@@ -121,6 +134,17 @@ func componentConverter(specVersion SpecVersion) func(*Component) {
121
134
}
122
135
}
123
136
137
+ if specVersion < SpecVersion1_5 {
138
+ c .ModelCard = nil
139
+ c .Data = nil
140
+
141
+ if c .Evidence != nil {
142
+ c .Evidence .Identity = nil
143
+ c .Evidence .Occurrences = nil
144
+ c .Evidence .Callstack = nil
145
+ }
146
+ }
147
+
124
148
if ! specVersion .supportsComponentType (c .Type ) {
125
149
c .Type = ComponentTypeApplication
126
150
}
@@ -133,6 +157,19 @@ func componentConverter(specVersion SpecVersion) func(*Component) {
133
157
}
134
158
}
135
159
160
+ func convertCompositions (comps * []Composition , specVersion SpecVersion ) {
161
+ if comps == nil {
162
+ return
163
+ }
164
+
165
+ for i := range * comps {
166
+ comp := & (* comps )[i ]
167
+ if ! specVersion .supportsCompositionAggregate (comp .Aggregate ) {
168
+ comp .Aggregate = CompositionAggregateUnknown
169
+ }
170
+ }
171
+ }
172
+
136
173
// convertExternalReferences modifies an ExternalReference slice such that it adheres to a given SpecVersion.
137
174
func convertExternalReferences (extRefs * []ExternalReference , specVersion SpecVersion ) {
138
175
if extRefs == nil {
@@ -218,6 +255,33 @@ func convertLicenses(licenses *Licenses, specVersion SpecVersion) {
218
255
}
219
256
}
220
257
258
+ func convertVulnerabilities (vulns * []Vulnerability , specVersion SpecVersion ) {
259
+ if vulns == nil {
260
+ return
261
+ }
262
+
263
+ for i := range * vulns {
264
+ vuln := & (* vulns )[i ]
265
+
266
+ convertTools (vuln .Tools , specVersion )
267
+
268
+ if specVersion < SpecVersion1_5 {
269
+ vuln .ProofOfConcept = nil
270
+ vuln .Rejected = ""
271
+ vuln .Workaround = ""
272
+ }
273
+
274
+ if vuln .Ratings != nil {
275
+ for j := range * vuln .Ratings {
276
+ rating := & (* vuln .Ratings )[j ]
277
+ if ! specVersion .supportsScoringMethod (rating .Method ) {
278
+ rating .Method = ScoringMethodOther
279
+ }
280
+ }
281
+ }
282
+ }
283
+ }
284
+
221
285
// serviceConverter modifies a Service such that it adheres to a given SpecVersion.
222
286
func serviceConverter (specVersion SpecVersion ) func (* Service ) {
223
287
return func (s * Service ) {
@@ -233,6 +297,50 @@ func serviceConverter(specVersion SpecVersion) func(*Service) {
233
297
}
234
298
}
235
299
300
+ // convertTools modifies a ToolsChoice such that it adheres to a given SpecVersion.
301
+ func convertTools (tools * ToolsChoice , specVersion SpecVersion ) {
302
+ if tools == nil {
303
+ return
304
+ }
305
+
306
+ if specVersion < SpecVersion1_5 {
307
+ convertedTools := make ([]Tool , 0 )
308
+ if tools .Components != nil {
309
+ for i := range * tools .Components {
310
+ tool := convertComponentToTool ((* tools .Components )[i ], specVersion )
311
+ if tool != nil {
312
+ convertedTools = append (convertedTools , * tool )
313
+ }
314
+ }
315
+ tools .Components = nil
316
+ }
317
+
318
+ if tools .Services != nil {
319
+ for i := range * tools .Services {
320
+ tool := convertServiceToTool ((* tools .Services )[i ], specVersion )
321
+ if tool != nil {
322
+ convertedTools = append (convertedTools , * tool )
323
+ }
324
+ }
325
+ tools .Services = nil
326
+ }
327
+
328
+ if len (convertedTools ) > 0 {
329
+ if tools .Tools == nil {
330
+ tools .Tools = & convertedTools
331
+ } else {
332
+ * tools .Tools = append (* tools .Tools , convertedTools ... )
333
+ }
334
+ }
335
+ }
336
+
337
+ if tools .Tools != nil {
338
+ for i := range * tools .Tools {
339
+ convertTool (& (* tools .Tools )[i ], specVersion )
340
+ }
341
+ }
342
+ }
343
+
236
344
// convertTool modifies a Tool such that it adheres to a given SpecVersion.
237
345
func convertTool (tool * Tool , specVersion SpecVersion ) {
238
346
if tool == nil {
@@ -247,6 +355,40 @@ func convertTool(tool *Tool, specVersion SpecVersion) {
247
355
convertHashes (tool .Hashes , specVersion )
248
356
}
249
357
358
+ // convertComponentToTool converts a Component to a Tool for use in ToolsChoice.Tools.
359
+ func convertComponentToTool (component Component , _ SpecVersion ) * Tool {
360
+ tool := Tool {
361
+ Vendor : component .Author ,
362
+ Name : component .Name ,
363
+ Version : component .Version ,
364
+ Hashes : component .Hashes ,
365
+ ExternalReferences : component .ExternalReferences ,
366
+ }
367
+
368
+ if component .Supplier != nil {
369
+ // There is no perfect 1:1 mapping for the Vendor field, but Supplier comes closest.
370
+ // https://github.com/CycloneDX/cyclonedx-go/issues/115#issuecomment-1688710539
371
+ tool .Vendor = component .Supplier .Name
372
+ }
373
+
374
+ return & tool
375
+ }
376
+
377
+ // convertServiceToTool converts a Service to a Tool for use in ToolsChoice.Tools.
378
+ func convertServiceToTool (service Service , _ SpecVersion ) * Tool {
379
+ tool := Tool {
380
+ Name : service .Name ,
381
+ Version : service .Version ,
382
+ ExternalReferences : service .ExternalReferences ,
383
+ }
384
+
385
+ if service .Provider != nil {
386
+ tool .Vendor = service .Provider .Name
387
+ }
388
+
389
+ return & tool
390
+ }
391
+
250
392
func recurseComponent (component * Component , f func (c * Component )) {
251
393
if component == nil {
252
394
return
@@ -307,17 +449,32 @@ func (sv SpecVersion) supportsComponentType(cType ComponentType) bool {
307
449
return false
308
450
}
309
451
452
+ func (sv SpecVersion ) supportsCompositionAggregate (ca CompositionAggregate ) bool {
453
+ switch ca {
454
+ case CompositionAggregateIncompleteFirstPartyOpenSourceOnly , CompositionAggregateIncompleteFirstPartyProprietaryOnly ,
455
+ CompositionAggregateIncompleteThirdPartyOpenSourceOnly , CompositionAggregateIncompleteThirdPartyProprietaryOnly :
456
+ return sv >= SpecVersion1_5
457
+ }
458
+
459
+ return sv >= SpecVersion1_3
460
+ }
461
+
310
462
func (sv SpecVersion ) supportsExternalReferenceType (ert ExternalReferenceType ) bool {
311
463
switch ert {
312
464
case ERTypeAdversaryModel ,
313
465
ERTypeAttestation ,
314
466
ERTypeCertificationReport ,
315
467
ERTypeCodifiedInfrastructure ,
316
468
ERTypeComponentAnalysisReport ,
469
+ ERTypeConfiguration ,
317
470
ERTypeDistributionIntake ,
318
471
ERTypeDynamicAnalysisReport ,
472
+ ERTypeEvidence ,
319
473
ERTypeExploitabilityStatement ,
474
+ ERTypeFormulation ,
475
+ ERTypeLog ,
320
476
ERTypeMaturityReport ,
477
+ ERTypeModelCard ,
321
478
ERTypePentestReport ,
322
479
ERTypeQualityMetrics ,
323
480
ERTypeRiskAssessment ,
@@ -352,3 +509,14 @@ func (sv SpecVersion) supportsScope(scope Scope) bool {
352
509
353
510
return false
354
511
}
512
+
513
+ func (sv SpecVersion ) supportsScoringMethod (method ScoringMethod ) bool {
514
+ switch method {
515
+ case ScoringMethodCVSSv2 , ScoringMethodCVSSv3 , ScoringMethodCVSSv31 , ScoringMethodOWASP , ScoringMethodOther :
516
+ return sv >= SpecVersion1_4
517
+ case ScoringMethodCVSSv4 , ScoringMethodSSVC :
518
+ return sv >= SpecVersion1_5
519
+ }
520
+
521
+ return false
522
+ }
0 commit comments