Skip to content

Commit b9654ae

Browse files
authored
Merge pull request #90 from CycloneDX/spec-v1.5
feat: add support for spec v1.5
2 parents 55ff321 + 64eb0c8 commit b9654ae

File tree

49 files changed

+3713
-278
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+3713
-278
lines changed

.golangci.yml

+1-10
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,6 @@ linters:
22
enable:
33
- asciicheck
44
- errorlint
5-
- gci
6-
- gofumpt
5+
- gofmt
76
- gosec
87
- wastedassign
9-
10-
linters-settings:
11-
gci:
12-
sections:
13-
- standard
14-
- default
15-
- prefix(github.com/CycloneDX)
16-
custom-order: true

convert.go

+173-5
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ func (b *BOM) convert(specVersion SpecVersion) {
5050
}
5151
if specVersion < SpecVersion1_5 {
5252
b.Annotations = nil
53+
b.Formulation = nil
5354
}
5455

5556
if b.Metadata != nil {
@@ -61,13 +62,13 @@ func (b *BOM) convert(specVersion SpecVersion) {
6162
b.Metadata.Lifecycles = nil
6263
}
6364

65+
if specVersion < SpecVersion1_5 {
66+
b.Metadata.Lifecycles = nil
67+
}
68+
6469
recurseComponent(b.Metadata.Component, componentConverter(specVersion))
6570
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)
7172
}
7273

7374
if b.Components != nil {
@@ -82,6 +83,18 @@ func (b *BOM) convert(specVersion SpecVersion) {
8283
}
8384
}
8485

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+
8598
b.SpecVersion = specVersion
8699
b.XMLNS = xmlNamespaces[specVersion]
87100
b.JSONSchema = jsonSchemas[specVersion]
@@ -121,6 +134,17 @@ func componentConverter(specVersion SpecVersion) func(*Component) {
121134
}
122135
}
123136

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+
124148
if !specVersion.supportsComponentType(c.Type) {
125149
c.Type = ComponentTypeApplication
126150
}
@@ -133,6 +157,19 @@ func componentConverter(specVersion SpecVersion) func(*Component) {
133157
}
134158
}
135159

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+
136173
// convertExternalReferences modifies an ExternalReference slice such that it adheres to a given SpecVersion.
137174
func convertExternalReferences(extRefs *[]ExternalReference, specVersion SpecVersion) {
138175
if extRefs == nil {
@@ -218,6 +255,33 @@ func convertLicenses(licenses *Licenses, specVersion SpecVersion) {
218255
}
219256
}
220257

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+
221285
// serviceConverter modifies a Service such that it adheres to a given SpecVersion.
222286
func serviceConverter(specVersion SpecVersion) func(*Service) {
223287
return func(s *Service) {
@@ -233,6 +297,50 @@ func serviceConverter(specVersion SpecVersion) func(*Service) {
233297
}
234298
}
235299

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+
236344
// convertTool modifies a Tool such that it adheres to a given SpecVersion.
237345
func convertTool(tool *Tool, specVersion SpecVersion) {
238346
if tool == nil {
@@ -247,6 +355,40 @@ func convertTool(tool *Tool, specVersion SpecVersion) {
247355
convertHashes(tool.Hashes, specVersion)
248356
}
249357

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+
250392
func recurseComponent(component *Component, f func(c *Component)) {
251393
if component == nil {
252394
return
@@ -307,17 +449,32 @@ func (sv SpecVersion) supportsComponentType(cType ComponentType) bool {
307449
return false
308450
}
309451

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+
310462
func (sv SpecVersion) supportsExternalReferenceType(ert ExternalReferenceType) bool {
311463
switch ert {
312464
case ERTypeAdversaryModel,
313465
ERTypeAttestation,
314466
ERTypeCertificationReport,
315467
ERTypeCodifiedInfrastructure,
316468
ERTypeComponentAnalysisReport,
469+
ERTypeConfiguration,
317470
ERTypeDistributionIntake,
318471
ERTypeDynamicAnalysisReport,
472+
ERTypeEvidence,
319473
ERTypeExploitabilityStatement,
474+
ERTypeFormulation,
475+
ERTypeLog,
320476
ERTypeMaturityReport,
477+
ERTypeModelCard,
321478
ERTypePentestReport,
322479
ERTypeQualityMetrics,
323480
ERTypeRiskAssessment,
@@ -352,3 +509,14 @@ func (sv SpecVersion) supportsScope(scope Scope) bool {
352509

353510
return false
354511
}
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

Comments
 (0)