Skip to content

Commit 692c005

Browse files
committed
addressed JSON output for #275 including test addiitions
Signed-off-by: Paul Horton <[email protected]>
1 parent 6597db7 commit 692c005

8 files changed

+1017
-124
lines changed

cyclonedx/output/json.py

Lines changed: 61 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,9 @@ def _specialise_output_for_schema_version(self, bom_json: Dict[Any, Any]) -> str
115115
del bom_json['metadata']['properties']
116116

117117
# Iterate Components
118+
if self.get_bom().metadata.component:
119+
bom_json['metadata'] = self._recurse_specialise_component(bom_json=bom_json['metadata'],
120+
base_key='component')
118121
bom_json = self._recurse_specialise_component(bom_json=bom_json)
119122

120123
# Iterate Services
@@ -155,60 +158,67 @@ def _get_schema_uri(self) -> Optional[str]:
155158

156159
def _recurse_specialise_component(self, bom_json: Dict[Any, Any], base_key: str = 'components') -> Dict[Any, Any]:
157160
if base_key in bom_json.keys():
158-
for i in range(len(bom_json[base_key])):
159-
if not self.component_supports_mime_type_attribute() \
160-
and 'mime-type' in bom_json[base_key][i].keys():
161-
del bom_json[base_key][i]['mime-type']
162-
163-
if not self.component_supports_supplier() and 'supplier' in bom_json[base_key][i].keys():
164-
del bom_json[base_key][i]['supplier']
165-
166-
if not self.component_supports_author() and 'author' in bom_json[base_key][i].keys():
167-
del bom_json[base_key][i]['author']
168-
169-
if self.component_version_optional() and 'version' in bom_json[base_key][i] \
170-
and bom_json[base_key][i].get('version', '') == "":
171-
del bom_json[base_key][i]['version']
172-
173-
if not self.component_supports_pedigree() and 'pedigree' in bom_json[base_key][i].keys():
174-
del bom_json[base_key][i]['pedigree']
175-
elif 'pedigree' in bom_json[base_key][i].keys():
176-
if 'ancestors' in bom_json[base_key][i]['pedigree'].keys():
177-
# recurse into ancestors
178-
bom_json[base_key][i]['pedigree'] = self._recurse_specialise_component(
179-
bom_json=bom_json[base_key][i]['pedigree'], base_key='ancestors'
180-
)
181-
if 'descendants' in bom_json[base_key][i]['pedigree'].keys():
182-
# recurse into descendants
183-
bom_json[base_key][i]['pedigree'] = self._recurse_specialise_component(
184-
bom_json=bom_json[base_key][i]['pedigree'], base_key='descendants'
185-
)
186-
if 'variants' in bom_json[base_key][i]['pedigree'].keys():
187-
# recurse into variants
188-
bom_json[base_key][i]['pedigree'] = self._recurse_specialise_component(
189-
bom_json=bom_json[base_key][i]['pedigree'], base_key='variants'
190-
)
191-
192-
if not self.external_references_supports_hashes() and 'externalReferences' \
193-
in bom_json[base_key][i].keys():
194-
for j in range(len(bom_json[base_key][i]['externalReferences'])):
195-
del bom_json[base_key][i]['externalReferences'][j]['hashes']
196-
197-
if not self.component_supports_properties() and 'properties' in bom_json[base_key][i].keys():
198-
del bom_json[base_key][i]['properties']
199-
200-
# recurse
201-
if 'components' in bom_json[base_key][i].keys():
202-
bom_json[base_key][i] = self._recurse_specialise_component(bom_json=bom_json[base_key][i])
203-
204-
if not self.component_supports_evidence() and 'evidence' in bom_json[base_key][i].keys():
205-
del bom_json[base_key][i]['evidence']
206-
207-
if not self.component_supports_release_notes() and 'releaseNotes' in bom_json[base_key][i].keys():
208-
del bom_json[base_key][i]['releaseNotes']
161+
if isinstance(bom_json[base_key], dict):
162+
bom_json[base_key] = self._specialise_component_data(component_json=bom_json[base_key])
163+
else:
164+
for i in range(len(bom_json[base_key])):
165+
bom_json[base_key][i] = self._specialise_component_data(component_json=bom_json[base_key][i])
209166

210167
return bom_json
211168

169+
def _specialise_component_data(self, component_json: Dict[Any, Any]) -> Dict[Any, Any]:
170+
if not self.component_supports_mime_type_attribute() and 'mime-type' in component_json.keys():
171+
del component_json['mime-type']
172+
173+
if not self.component_supports_supplier() and 'supplier' in component_json.keys():
174+
del component_json['supplier']
175+
176+
if not self.component_supports_author() and 'author' in component_json.keys():
177+
del component_json['author']
178+
179+
if self.component_version_optional() and 'version' in component_json \
180+
and component_json.get('version', '') == "":
181+
del component_json['version']
182+
183+
if not self.component_supports_pedigree() and 'pedigree' in component_json.keys():
184+
del component_json['pedigree']
185+
elif 'pedigree' in component_json.keys():
186+
if 'ancestors' in component_json['pedigree'].keys():
187+
# recurse into ancestors
188+
component_json['pedigree'] = self._recurse_specialise_component(
189+
bom_json=component_json['pedigree'], base_key='ancestors'
190+
)
191+
if 'descendants' in component_json['pedigree'].keys():
192+
# recurse into descendants
193+
component_json['pedigree'] = self._recurse_specialise_component(
194+
bom_json=component_json['pedigree'], base_key='descendants'
195+
)
196+
if 'variants' in component_json['pedigree'].keys():
197+
# recurse into variants
198+
component_json['pedigree'] = self._recurse_specialise_component(
199+
bom_json=component_json['pedigree'], base_key='variants'
200+
)
201+
202+
if not self.external_references_supports_hashes() and 'externalReferences' \
203+
in component_json.keys():
204+
for j in range(len(component_json['externalReferences'])):
205+
del component_json['externalReferences'][j]['hashes']
206+
207+
if not self.component_supports_properties() and 'properties' in component_json.keys():
208+
del component_json['properties']
209+
210+
# recurse
211+
if 'components' in component_json.keys():
212+
component_json = self._recurse_specialise_component(bom_json=component_json)
213+
214+
if not self.component_supports_evidence() and 'evidence' in component_json.keys():
215+
del component_json['evidence']
216+
217+
if not self.component_supports_release_notes() and 'releaseNotes' in component_json.keys():
218+
del component_json['releaseNotes']
219+
220+
return component_json
221+
212222

213223
class JsonV1Dot0(Json, SchemaVersion1Dot0):
214224

tests/data.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ def get_bom_with_component_toml_1() -> Bom:
210210
def get_bom_just_complete_metadata() -> Bom:
211211
bom = Bom()
212212
bom.metadata.authors = [get_org_contact_1(), get_org_contact_2()]
213-
bom.metadata.component = get_component_setuptools_complete(include_pedigree=False)
213+
bom.metadata.component = get_component_setuptools_complete()
214214
bom.metadata.manufacture = get_org_entity_1()
215215
bom.metadata.supplier = get_org_entity_2()
216216
bom.metadata.licenses = [LicenseChoice(license_=License(
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
{
2+
"$schema": "http://cyclonedx.org/schema/bom-1.2b.schema.json",
3+
"bomFormat": "CycloneDX",
4+
"components": [
5+
{
6+
"bom-ref": "17e3b199-dc0b-42ef-bfdd-1fa81a1e3eda",
7+
"name": "comp_a",
8+
"type": "library",
9+
"version": "1.0.0"
10+
},
11+
{
12+
"bom-ref": "0b049d09-64c0-4490-a0f5-c84d9aacf857",
13+
"components": [
14+
{
15+
"bom-ref": "cd3e9c95-9d41-49e7-9924-8cf0465ae789",
16+
"name": "comp_c",
17+
"type": "library",
18+
"version": "1.0.0"
19+
}
20+
],
21+
"name": "comp_b",
22+
"type": "library",
23+
"version": "1.0.0"
24+
}
25+
],
26+
"dependencies": [
27+
{
28+
"dependsOn": [
29+
"17e3b199-dc0b-42ef-bfdd-1fa81a1e3eda",
30+
"0b049d09-64c0-4490-a0f5-c84d9aacf857"
31+
],
32+
"ref": "be2c6502-7e9a-47db-9a66-e34f729810a3"
33+
},
34+
{
35+
"dependsOn": [],
36+
"ref": "17e3b199-dc0b-42ef-bfdd-1fa81a1e3eda"
37+
},
38+
{
39+
"dependsOn": [
40+
"cd3e9c95-9d41-49e7-9924-8cf0465ae789"
41+
],
42+
"ref": "0b049d09-64c0-4490-a0f5-c84d9aacf857"
43+
}
44+
],
45+
"metadata": {
46+
"component": {
47+
"bom-ref": "be2c6502-7e9a-47db-9a66-e34f729810a3",
48+
"name": "app",
49+
"type": "library",
50+
"version": "1.0.0"
51+
},
52+
"timestamp": "2022-07-27T10:06:17.101289+00:00",
53+
"tools": [
54+
{
55+
"name": "cyclonedx-python-lib",
56+
"vendor": "CycloneDX",
57+
"version": "0.11.0"
58+
}
59+
]
60+
},
61+
"serialNumber": "urn:uuid:b1d647c9-e4c5-4d8f-be8a-1751ac3ad4d5",
62+
"specVersion": "1.2",
63+
"version": 1
64+
}

0 commit comments

Comments
 (0)