Skip to content

Commit 1bd0e4d

Browse files
authored
Workaround a loading issue with cyclonedx-python-lib #1185 (#1186)
Signed-off-by: tdruez <tdruez@nexb.com>
1 parent 0bdb8d3 commit 1bd0e4d

File tree

4 files changed

+45
-6
lines changed

4 files changed

+45
-6
lines changed

CHANGELOG.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@ v34.5.0 (unreleased)
1515
symbol, string and comments using Pygments.
1616
https://github.com/nexB/scancode.io/pull/1179
1717

18+
- Workaround an issue with the cyclonedx-python-lib that does not allow to load
19+
SBOMs that contains properties with no values.
20+
https://github.com/nexB/scancode.io/issues/1185
21+
1822
v34.4.0 (2024-04-22)
1923
--------------------
2024

scanpipe/pipes/cyclonedx.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,7 @@ def delete_tools(cyclonedx_document_json):
189189
190190
The new structure is not yet supported by the cyclonedx-python-lib, neither for
191191
serialization (output) nor deserialization (input).
192+
https://github.com/CycloneDX/cyclonedx-python-lib/issues/578
192193
193194
The tools are not used anyway in the context of loading the SBOM component data as
194195
packages.
@@ -199,6 +200,30 @@ def delete_tools(cyclonedx_document_json):
199200
return cyclonedx_document_json
200201

201202

203+
def delete_empty_dict_property(cyclonedx_document_json):
204+
"""
205+
Remove dict entry where keys are defined but no values are set, such as
206+
``{"name": ""}``.
207+
208+
Class like cyclonedx.model.contact.OrganizationalEntity raise a
209+
NoPropertiesProvidedException while it is not enforced in the spec.
210+
211+
See https://github.com/CycloneDX/cyclonedx-python-lib/issues/600
212+
"""
213+
entries_to_delete = []
214+
215+
for component in cyclonedx_document_json["components"]:
216+
for property_name, property_value in component.items():
217+
if isinstance(property_value, dict) and not any(property_value.values()):
218+
entries_to_delete.append((component, property_name))
219+
220+
# Now delete the keys outside the loop
221+
for component, property_name in entries_to_delete:
222+
del component[property_name]
223+
224+
return cyclonedx_document_json
225+
226+
202227
def resolve_cyclonedx_packages(input_location):
203228
"""Resolve the packages from the `input_location` CycloneDX document file."""
204229
input_path = Path(input_location)
@@ -215,7 +240,9 @@ def resolve_cyclonedx_packages(input_location):
215240
f'CycloneDX document "{input_path.name}" is not valid:\n{errors}'
216241
)
217242
raise ValueError(error_msg)
243+
218244
cyclonedx_document = delete_tools(cyclonedx_document)
245+
cyclonedx_document = delete_empty_dict_property(cyclonedx_document)
219246
cyclonedx_bom = Bom.from_json(data=cyclonedx_document)
220247

221248
else:

scanpipe/pipes/resolve.py

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,16 @@
4242
"""
4343

4444

45+
def resolve_manifest_resources(resource, package_registry):
46+
"""Get package data from resource."""
47+
packages = get_packages_from_manifest(resource.location, package_registry) or []
48+
49+
for package_data in packages:
50+
package_data["codebase_resources"] = [resource]
51+
52+
return packages
53+
54+
4555
def get_packages(project, package_registry, manifest_resources, model=None):
4656
"""
4757
Get package data from package manifests/lockfiles/SBOMs or
@@ -51,15 +61,13 @@ def get_packages(project, package_registry, manifest_resources, model=None):
5161

5262
if not manifest_resources.exists():
5363
project.add_warning(
54-
description="No resources found with package data",
64+
description="No resources containing package data found in codebase.",
5565
model=model,
5666
)
57-
return
67+
return []
5868

5969
for resource in manifest_resources:
60-
if packages := get_packages_from_manifest(resource.location, package_registry):
61-
for package_data in packages:
62-
package_data["codebase_resources"] = [resource]
70+
if packages := resolve_manifest_resources(resource, package_registry):
6371
resolved_packages.extend(packages)
6472
else:
6573
project.add_error(

scanpipe/tests/test_pipelines.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -900,7 +900,7 @@ def test_scanpipe_resolve_dependencies_pipeline_integration(self):
900900
self.assertEqual(1, project1.projectmessages.count())
901901
message = project1.projectmessages.get()
902902
self.assertEqual("get_packages_from_manifest", message.model)
903-
expected = "No resources found with package data"
903+
expected = "No resources containing package data found in codebase."
904904
self.assertIn(expected, message.description)
905905

906906
def test_scanpipe_resolve_dependencies_pipeline_integration_empty_manifest(self):

0 commit comments

Comments
 (0)