Skip to content

Commit

Permalink
Add support for CycloneDX SBOM component properties from external tools
Browse files Browse the repository at this point in the history
Signed-off-by: tdruez <[email protected]>
  • Loading branch information
tdruez committed May 17, 2024
1 parent 47bfef4 commit b20822b
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 6 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ v34.5.0 (unreleased)
- Remove the ``scancode_license_score`` option from the Project configuration.
https://github.com/nexB/scancode.io/issues/1231

- Add support for CycloneDX SBOM component properties as generated by external tools.
For example, the ``ResolvedUrl`` generated by cdxgen is now imported as the package
``download_url``.

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

Expand Down
26 changes: 20 additions & 6 deletions scanpipe/pipes/cyclonedx.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,14 +88,28 @@ def get_properties_data(component):
"""Return the properties as dict, extracted from `component.properties`."""
prefix = "aboutcode:"
properties_data = {}
properties = component.properties or []
properties_dict = {
component_property.name: component_property.value
for component_property in component.properties
}

for component_property in properties:
property_name = component_property.name
property_value = component_property.value
for property_name, property_value in properties_dict.items():
if property_name.startswith(prefix) and property_value not in EMPTY_VALUES:
field_name = property_name.replace(prefix, "", 1)
properties_data[field_name] = property_value
package_field_name = property_name.replace(prefix, "", 1)
properties_data[package_field_name] = property_value

# Mapping of few other properties found in SBOM generated by external tools.
property_mapping = {
"ResolvedUrl": "download_url", # generated by "CycloneDX/cdxgen"
}

for property_name, package_field_name in property_mapping.items():
if properties_data.get(package_field_name) not in EMPTY_VALUES:
continue # Skip if a value is already set for that field

property_value = properties_dict.get(property_name)
if property_value not in EMPTY_VALUES:
properties_data[package_field_name] = property_value

return properties_data

Expand Down
16 changes: 16 additions & 0 deletions scanpipe/tests/pipes/test_cyclonedx.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

from django.test import TestCase

from cyclonedx.model import Property
from cyclonedx.model import license as cdx_license_model
from cyclonedx.model.bom import Bom
from cyclonedx.model.component import Component
Expand Down Expand Up @@ -133,6 +134,21 @@ def test_scanpipe_cyclonedx_get_properties_data(self):
}
self.assertEqual(expected, properties_data)

resolved_url_property = Property(
name="ResolvedUrl", value="https://download.url/resolved.tar.gz"
)
self.component3.properties.add(resolved_url_property)
properties_data = cyclonedx.get_properties_data(self.component3)
# Same result as the "aboutcode:download_url" takes precedence.
self.assertEqual(expected, properties_data)

self.component3.properties = {resolved_url_property}
properties_data = cyclonedx.get_properties_data(self.component3)
expected = {
"download_url": "https://download.url/resolved.tar.gz",
}
self.assertEqual(expected, properties_data)

def test_scanpipe_cyclonedx_validate_document(self):
error = cyclonedx.validate_document(document="{}")
self.assertIsInstance(error, ValidationError)
Expand Down

0 comments on commit b20822b

Please sign in to comment.