diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 98b3f53653..0ef978b087 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -23,6 +23,12 @@ v35.4.0 (unreleased) - Add a Resources tree view. https://github.com/aboutcode-org/scancode.io/issues/1682 +- Improve CycloneDX SBOM support. + * Upgrade the cyclonedx-python-lib to 11.0.0 + * Fix the validate_document following library upgrade. + * Add support when the "components" entry is missing. + https://github.com/aboutcode-org/scancode.io/issues/1727 + v35.3.0 (2025-08-20) -------------------- diff --git a/pyproject.toml b/pyproject.toml index 41fcc1d28c..94ae1b1deb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -82,8 +82,8 @@ dependencies = [ # Profiling "pyinstrument==5.1.1", # CycloneDX - "cyclonedx-python-lib==10.2.0", - "jsonschema==4.24.0", + "cyclonedx-python-lib==11.0.0", + "jsonschema==4.25.1", # MatchCode-toolkit "matchcode-toolkit==7.2.2", # Univers diff --git a/scanpipe/pipes/cyclonedx.py b/scanpipe/pipes/cyclonedx.py index f6837404b5..bba33e18bb 100644 --- a/scanpipe/pipes/cyclonedx.py +++ b/scanpipe/pipes/cyclonedx.py @@ -123,7 +123,10 @@ def validate_document(document): The validator is loaded from the document specVersion property. """ if isinstance(document, str): + document_str = document document = json.loads(document) + else: + document_str = json.dumps(document) spec_version = document.get("specVersion") if not spec_version: @@ -132,7 +135,8 @@ def validate_document(document): schema_version = SchemaVersion.from_version(spec_version) json_validator = JsonStrictValidator(schema_version) - return json_validator._validata_data(document) + json_validation_errors = json_validator.validate_str(document_str) + return json_validation_errors def is_cyclonedx_bom(input_location): @@ -281,7 +285,7 @@ def is_empty(value): elif isinstance(value, list) and not any(value): return True - for component in cyclonedx_document_json["components"]: + for component in cyclonedx_document_json.get("components", []): for property_name, property_value in component.items(): if is_empty(property_value) or property_name in ignored_properties: entries_to_delete.append((component, property_name)) diff --git a/scanpipe/tests/data/cyclonedx/missing_components.json b/scanpipe/tests/data/cyclonedx/missing_components.json new file mode 100644 index 0000000000..ab57f7571f --- /dev/null +++ b/scanpipe/tests/data/cyclonedx/missing_components.json @@ -0,0 +1,21 @@ +{ + "$schema": "http://cyclonedx.org/schema/bom-1.6.schema.json", + "bomFormat": "CycloneDX", + "specVersion": "1.6", + "serialNumber": "urn:uuid:b74fe5df-e965-415e-ba65-f38421a0695d", + "version": 1, + "metadata": { + "component": { + "bom-ref": "804c3391-e6f9-415f-bb7a-cb6653853a46", + "name": "name", + "type": "library" + }, + "timestamp": "2024-03-07T17:05:37.329061+00:00", + "tools": [ + { + "name": "ScanCode.io", + "version": "0.0.0" + } + ] + } +} \ No newline at end of file diff --git a/scanpipe/tests/pipes/test_cyclonedx.py b/scanpipe/tests/pipes/test_cyclonedx.py index 27ddecc5b2..4687099793 100644 --- a/scanpipe/tests/pipes/test_cyclonedx.py +++ b/scanpipe/tests/pipes/test_cyclonedx.py @@ -270,6 +270,11 @@ def test_scanpipe_cyclonedx_resolve_cyclonedx_packages_pre_validation(self): expected = [{"name": "asgiref", "package_uid": "pkg:pypi/asgiref@3.3.0"}] self.assertEqual(expected, package_data) + def test_scanpipe_cyclonedx_resolve_cyclonedx_packages_missing_components(self): + input_location = self.data / "missing_components.json" + package_data = cyclonedx.resolve_cyclonedx_packages(input_location) + self.assertEqual([], package_data) + def test_scanpipe_cyclonedx_cleanup_components_properties(self): cyclonedx_document_json = { "components": [