Skip to content

Commit

Permalink
Workaround a loading issue with cyclonedx-python-lib #1185 (#1186)
Browse files Browse the repository at this point in the history
Signed-off-by: tdruez <[email protected]>
  • Loading branch information
tdruez authored Apr 26, 2024
1 parent 0bdb8d3 commit 1bd0e4d
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 6 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ v34.5.0 (unreleased)
symbol, string and comments using Pygments.
https://github.com/nexB/scancode.io/pull/1179

- Workaround an issue with the cyclonedx-python-lib that does not allow to load
SBOMs that contains properties with no values.
https://github.com/nexB/scancode.io/issues/1185

v34.4.0 (2024-04-22)
--------------------

Expand Down
27 changes: 27 additions & 0 deletions scanpipe/pipes/cyclonedx.py
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ def delete_tools(cyclonedx_document_json):
The new structure is not yet supported by the cyclonedx-python-lib, neither for
serialization (output) nor deserialization (input).
https://github.com/CycloneDX/cyclonedx-python-lib/issues/578
The tools are not used anyway in the context of loading the SBOM component data as
packages.
Expand All @@ -199,6 +200,30 @@ def delete_tools(cyclonedx_document_json):
return cyclonedx_document_json


def delete_empty_dict_property(cyclonedx_document_json):
"""
Remove dict entry where keys are defined but no values are set, such as
``{"name": ""}``.
Class like cyclonedx.model.contact.OrganizationalEntity raise a
NoPropertiesProvidedException while it is not enforced in the spec.
See https://github.com/CycloneDX/cyclonedx-python-lib/issues/600
"""
entries_to_delete = []

for component in cyclonedx_document_json["components"]:
for property_name, property_value in component.items():
if isinstance(property_value, dict) and not any(property_value.values()):
entries_to_delete.append((component, property_name))

# Now delete the keys outside the loop
for component, property_name in entries_to_delete:
del component[property_name]

return cyclonedx_document_json


def resolve_cyclonedx_packages(input_location):
"""Resolve the packages from the `input_location` CycloneDX document file."""
input_path = Path(input_location)
Expand All @@ -215,7 +240,9 @@ def resolve_cyclonedx_packages(input_location):
f'CycloneDX document "{input_path.name}" is not valid:\n{errors}'
)
raise ValueError(error_msg)

cyclonedx_document = delete_tools(cyclonedx_document)
cyclonedx_document = delete_empty_dict_property(cyclonedx_document)
cyclonedx_bom = Bom.from_json(data=cyclonedx_document)

else:
Expand Down
18 changes: 13 additions & 5 deletions scanpipe/pipes/resolve.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,16 @@
"""


def resolve_manifest_resources(resource, package_registry):
"""Get package data from resource."""
packages = get_packages_from_manifest(resource.location, package_registry) or []

for package_data in packages:
package_data["codebase_resources"] = [resource]

return packages


def get_packages(project, package_registry, manifest_resources, model=None):
"""
Get package data from package manifests/lockfiles/SBOMs or
Expand All @@ -51,15 +61,13 @@ def get_packages(project, package_registry, manifest_resources, model=None):

if not manifest_resources.exists():
project.add_warning(
description="No resources found with package data",
description="No resources containing package data found in codebase.",
model=model,
)
return
return []

for resource in manifest_resources:
if packages := get_packages_from_manifest(resource.location, package_registry):
for package_data in packages:
package_data["codebase_resources"] = [resource]
if packages := resolve_manifest_resources(resource, package_registry):
resolved_packages.extend(packages)
else:
project.add_error(
Expand Down
2 changes: 1 addition & 1 deletion scanpipe/tests/test_pipelines.py
Original file line number Diff line number Diff line change
Expand Up @@ -900,7 +900,7 @@ def test_scanpipe_resolve_dependencies_pipeline_integration(self):
self.assertEqual(1, project1.projectmessages.count())
message = project1.projectmessages.get()
self.assertEqual("get_packages_from_manifest", message.model)
expected = "No resources found with package data"
expected = "No resources containing package data found in codebase."
self.assertIn(expected, message.description)

def test_scanpipe_resolve_dependencies_pipeline_integration_empty_manifest(self):
Expand Down

0 comments on commit 1bd0e4d

Please sign in to comment.