Skip to content

Commit 77a7a61

Browse files
committed
fix: BaseSerializer discriminate nested components
fixes #175 Signed-off-by: Jan Kowalleck <[email protected]>
1 parent 95d5f23 commit 77a7a61

File tree

4 files changed

+124
-5
lines changed

4 files changed

+124
-5
lines changed

HISTORY.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,14 @@ All notable changes to this project will be documented in this file.
44

55
## unreleased
66

7+
* Fixed
8+
* All serializers render unique `bom-ref` values of nested components. ([#175] via [#176])
79
* Misc
8-
* Improved readability of constructor parameter types. (via [#166])
10+
* Improved readability of constructor parameter types. (via [#166])
911

1012
[#166]: https://github.com/CycloneDX/cyclonedx-javascript-library/pull/166
13+
[#175]: https://github.com/CycloneDX/cyclonedx-javascript-library/issues/175
14+
[#176]: https://github.com/CycloneDX/cyclonedx-javascript-library/pull/176
1115

1216
## 1.3.1 - 2022-08-04
1317

src/serialize/baseSerializer.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ SPDX-License-Identifier: Apache-2.0
1717
Copyright (c) OWASP Foundation. All Rights Reserved.
1818
*/
1919

20-
import { Bom, BomRef } from '../models'
20+
import { Component, Bom, BomRef } from '../models'
2121
import { BomRefDiscriminator } from './bomRefDiscriminator'
2222
import { NormalizerOptions, Serializer, SerializerOptions } from './types'
2323

@@ -38,12 +38,19 @@ export abstract class BaseSerializer<NormalizedBom> implements Serializer {
3838

3939
#getAllBomRefs (bom: Bom): Iterable<BomRef> {
4040
const bomRefs = new Set<BomRef>()
41+
function iterComponents (cs: Iterable<Component>): void {
42+
for (const { bomRef, components } of cs) {
43+
bomRefs.add(bomRef)
44+
iterComponents(components)
45+
}
46+
}
47+
4148
if (bom.metadata.component !== undefined) {
4249
bomRefs.add(bom.metadata.component.bomRef)
50+
iterComponents(bom.metadata.component.components)
4351
}
44-
for (const { bomRef } of bom.components) {
45-
bomRefs.add(bomRef)
46-
}
52+
iterComponents(bom.components)
53+
4754
return bomRefs.values()
4855
}
4956

tests/integration/Serialize.JsonSerialize.test.js

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ const { createComplexStructure } = require('../_data/models')
2525
const { loadSerializeResult, writeSerializeResult } = require('../_data/serialize')
2626

2727
const {
28+
Models, Enums,
2829
Serialize: {
2930
JSON: { Normalize: { Factory: JsonNormalizeFactory } },
3031
JsonSerializer
@@ -52,6 +53,7 @@ describe('Serialize.JsonSerialize', function () {
5253

5354
it('serialize', function () {
5455
const serializer = new JsonSerializer(normalizerFactory)
56+
5557
const serialized = serializer.serialize(
5658
this.bom, {
5759
sortLists: true,
@@ -69,4 +71,56 @@ describe('Serialize.JsonSerialize', function () {
6971

7072
// TODO add more tests
7173
}))
74+
75+
describe('make bom-refs unique', () => {
76+
it('as expected', () => {
77+
const bom = new Models.Bom({
78+
metadata: new Models.Metadata({
79+
component: new Models.Component(Enums.ComponentType.Library, 'root', {
80+
bomRef: 'testing',
81+
components: new Models.ComponentRepository([
82+
new Models.Component(Enums.ComponentType.Library, 'c2', {
83+
bomRef: 'testing'
84+
})
85+
])
86+
})
87+
}),
88+
components: new Models.ComponentRepository([
89+
new Models.Component(Enums.ComponentType.Library, 'c1', {
90+
bomRef: 'testing',
91+
components: new Models.ComponentRepository([
92+
new Models.Component(Enums.ComponentType.Library, 'c2', {
93+
bomRef: 'testing'
94+
})
95+
])
96+
})
97+
])
98+
})
99+
const knownBomRefs = [
100+
bom.metadata.component.bomRef,
101+
[...bom.metadata.component.components][0].bomRef,
102+
[...bom.components.values()][0].bomRef,
103+
[...[...bom.components][0].components][0].bomRef
104+
]
105+
const normalizedBomRefs = new Set(/* will be filled on call */)
106+
const bomNormalizer = {
107+
normalize: (bom) => {
108+
normalizedBomRefs.add(bom.metadata.component.bomRef.value)
109+
normalizedBomRefs.add([...bom.metadata.component.components][0].bomRef.value)
110+
normalizedBomRefs.add([...bom.components.values()][0].bomRef.value)
111+
normalizedBomRefs.add([...[...bom.components][0].components][0].bomRef.value)
112+
return {}
113+
}
114+
}
115+
const normalizerFactory = { makeForBom: () => bomNormalizer, spec: Spec1dot4 }
116+
const serializer = new JsonSerializer(normalizerFactory)
117+
118+
serializer.serialize(bom)
119+
120+
assert.strictEqual(normalizedBomRefs.has('testing'), true)
121+
assert.strictEqual(normalizedBomRefs.size, 4, 'not every value was unique')
122+
// everything back to before - all have
123+
knownBomRefs.forEach(({ value }) => assert.strictEqual(value, 'testing'))
124+
})
125+
})
72126
})

tests/integration/Serialize.XmlSerialize.test.js

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ const { createComplexStructure } = require('../_data/models')
2525
const { loadSerializeResult, writeSerializeResult } = require('../_data/serialize')
2626

2727
const {
28+
Models, Enums,
2829
Serialize: {
2930
XML: { Normalize: { Factory: XmlNormalizeFactory } },
3031
XmlSerializer
@@ -52,6 +53,7 @@ describe('Serialize.XmlSerialize', function () {
5253

5354
it('serialize', function () {
5455
const serializer = new XmlSerializer(normalizerFactory)
56+
5557
const serialized = serializer.serialize(
5658
this.bom, {
5759
sortLists: true,
@@ -69,4 +71,56 @@ describe('Serialize.XmlSerialize', function () {
6971

7072
// TODO add more tests
7173
}))
74+
75+
describe('make bom-refs unique', () => {
76+
it('as expected', () => {
77+
const bom = new Models.Bom({
78+
metadata: new Models.Metadata({
79+
component: new Models.Component(Enums.ComponentType.Library, 'root', {
80+
bomRef: 'testing',
81+
components: new Models.ComponentRepository([
82+
new Models.Component(Enums.ComponentType.Library, 'c2', {
83+
bomRef: 'testing'
84+
})
85+
])
86+
})
87+
}),
88+
components: new Models.ComponentRepository([
89+
new Models.Component(Enums.ComponentType.Library, 'c1', {
90+
bomRef: 'testing',
91+
components: new Models.ComponentRepository([
92+
new Models.Component(Enums.ComponentType.Library, 'c2', {
93+
bomRef: 'testing'
94+
})
95+
])
96+
})
97+
])
98+
})
99+
const knownBomRefs = [
100+
bom.metadata.component.bomRef,
101+
[...bom.metadata.component.components][0].bomRef,
102+
[...bom.components.values()][0].bomRef,
103+
[...[...bom.components][0].components][0].bomRef
104+
]
105+
const normalizedBomRefs = new Set(/* will be filled on call */)
106+
const bomNormalizer = {
107+
normalize: (bom) => {
108+
normalizedBomRefs.add(bom.metadata.component.bomRef.value)
109+
normalizedBomRefs.add([...bom.metadata.component.components][0].bomRef.value)
110+
normalizedBomRefs.add([...bom.components.values()][0].bomRef.value)
111+
normalizedBomRefs.add([...[...bom.components][0].components][0].bomRef.value)
112+
return { type: 'element', name: 'dummy' }
113+
}
114+
}
115+
const normalizerFactory = { makeForBom: () => bomNormalizer, spec: Spec1dot4 }
116+
const serializer = new XmlSerializer(normalizerFactory)
117+
118+
serializer.serialize(bom)
119+
120+
assert.strictEqual(normalizedBomRefs.has('testing'), true)
121+
assert.strictEqual(normalizedBomRefs.size, 4, 'not every value was unique')
122+
// everything back to before - all have
123+
knownBomRefs.forEach(({ value }) => assert.strictEqual(value, 'testing'))
124+
})
125+
})
72126
})

0 commit comments

Comments
 (0)