From dc36e278d0870f29492853da2c2e32ae13d756ae Mon Sep 17 00:00:00 2001 From: Jan Kowalleck Date: Sat, 7 Jan 2023 00:02:18 +0100 Subject: [PATCH] fix: correct metadata handling for some specification versions Signed-off-by: Jan Kowalleck --- cyclonedx/output/json.py | 65 ++++++++++++++++++++-------------------- tests/base.py | 30 +++++++++++-------- 2 files changed, 49 insertions(+), 46 deletions(-) diff --git a/cyclonedx/output/json.py b/cyclonedx/output/json.py index 4556f3d2..e7a60afe 100644 --- a/cyclonedx/output/json.py +++ b/cyclonedx/output/json.py @@ -97,44 +97,43 @@ def generate(self, force_regeneration: bool = False) -> None: self.generated = True def _specialise_output_for_schema_version(self, bom_json: Dict[Any, Any]) -> str: - if not self.bom_supports_metadata(): - if 'metadata' in bom_json.keys(): + if 'metadata' in bom_json.keys(): + if not self.bom_supports_metadata(): del bom_json['metadata'] + else: + if 'tools' in bom_json['metadata'].keys(): + if not self.bom_metadata_supports_tools(): + del bom_json['metadata']['tools'] + else: + if not self.bom_metadata_supports_tools_external_references(): + for _tool in bom_json['metadata']['tools']: + if 'externalReferences' in _tool.keys(): + del _tool['externalReferences'] + del _tool + if 'licenses' in bom_json['metadata'].keys() and not self.bom_metadata_supports_licenses(): + del bom_json['metadata']['licenses'] + if 'properties' in bom_json['metadata'].keys() and not self.bom_metadata_supports_properties(): + del bom_json['metadata']['properties'] + + if self.get_bom().metadata.component: + bom_json['metadata'] = self._recurse_specialise_component(bom_json['metadata'], 'component') + + bom_json = self._recurse_specialise_component(bom_json) - if not self.bom_metadata_supports_tools(): - del bom_json['metadata']['tools'] - elif not self.bom_metadata_supports_tools_external_references(): - for i in range(len(bom_json['metadata']['tools'])): - if 'externalReferences' in bom_json['metadata']['tools'][i].keys(): - del bom_json['metadata']['tools'][i]['externalReferences'] - - if not self.bom_metadata_supports_licenses() and 'licenses' in bom_json['metadata'].keys(): - del bom_json['metadata']['licenses'] - - if not self.bom_metadata_supports_properties() and 'properties' in bom_json['metadata'].keys(): - del bom_json['metadata']['properties'] - - # Iterate Components - if self.get_bom().metadata.component: - bom_json['metadata'] = self._recurse_specialise_component(bom_json=bom_json['metadata'], - base_key='component') - bom_json = self._recurse_specialise_component(bom_json=bom_json) - - # Iterate Services if 'services' in bom_json.keys(): - for i in range(len(bom_json['services'])): - if not self.services_supports_properties() and 'properties' in bom_json['services'][i].keys(): - del bom_json['services'][i]['properties'] - - if not self.services_supports_release_notes() and 'releaseNotes' in bom_json['services'][i].keys(): - del bom_json['services'][i]['releaseNotes'] + for _service in bom_json['services']: + if 'properties' in _service.keys() and not self.services_supports_properties(): + del _service['properties'] + if 'releaseNotes' in _service.keys() and not self.services_supports_release_notes(): + del _service['releaseNotes'] + del _service - # Iterate externalReferences if 'externalReferences' in bom_json.keys(): - for i in range(len(bom_json['externalReferences'])): - if not self.external_references_supports_hashes() \ - and 'hashes' in bom_json['externalReferences'][i].keys(): - del bom_json['externalReferences'][i]['hashes'] + if not self.external_references_supports_hashes(): + for _externalReference in bom_json['externalReferences']: + if 'hashes' in _externalReference.keys(): + del _externalReference['hashes'] + del _externalReference return json.dumps(bom_json) diff --git a/tests/base.py b/tests/base.py index be5a1314..6803725d 100644 --- a/tests/base.py +++ b/tests/base.py @@ -87,7 +87,8 @@ def assertEqualJsonBom(self, a: str, b: str) -> None: """ Remove UUID before comparison as this will be unique to each generation """ - ab, bb = json.loads(a), json.loads(b) + ab = json.loads(a) + bb = json.loads(b) # Null serialNumbers ab['serialNumber'] = single_uuid @@ -95,19 +96,22 @@ def assertEqualJsonBom(self, a: str, b: str) -> None: # Unify timestamps to ensure they will compare now = datetime.now(tz=timezone.utc) - ab['metadata']['timestamp'] = now.isoformat() - bb['metadata']['timestamp'] = now.isoformat() - # Align 'this' Tool Version - if 'tools' in ab['metadata'].keys(): - for i, tool in enumerate(ab['metadata']['tools']): - if tool['name'] == cyclonedx_lib_name: - ab['metadata']['tools'][i]['version'] = cyclonedx_lib_version - - if 'tools' in bb['metadata'].keys(): - for i, tool in enumerate(bb['metadata']['tools']): - if tool['name'] == cyclonedx_lib_name: - bb['metadata']['tools'][i]['version'] = cyclonedx_lib_version + if 'metadata' in ab.keys(): + ab['metadata']['timestamp'] = now.isoformat() + if 'tools' in ab['metadata'].keys(): + for tool in ab['metadata']['tools']: + if tool['name'] == cyclonedx_lib_name: + tool['version'] = cyclonedx_lib_version + del tool + + if 'metadata' in bb.keys(): + bb['metadata']['timestamp'] = now.isoformat() + if 'tools' in bb['metadata'].keys(): + for tool in bb['metadata']['tools']: + if tool['name'] == cyclonedx_lib_name: + tool['version'] = cyclonedx_lib_version + del tool self.assertEqualJson(json.dumps(ab), json.dumps(bb))