diff --git a/sbom.py b/sbom.py index 9a3cfa00..42130e4f 100644 --- a/sbom.py +++ b/sbom.py @@ -100,10 +100,15 @@ class CreationInfo(TypedDict): def spdx_id(value: LiteralString) -> str: """Encode a value into characters that are valid in an SPDX ID""" value_as_spdx_id = re.sub(r"[^a-zA-Z0-9.\-]+", "-", value) - # To avoid collisions we append a hash suffix. - suffix = hashlib.sha256(value.encode()).hexdigest()[:8] - value_as_spdx_id = f"{value_as_spdx_id}-{suffix}" - assert _SPDX_IDS_TO_VALUES.setdefault(value_as_spdx_id, value) == value + + # The happy path is there are no collisions. + # But collisions can happen, especially in file paths. + # We append a hash suffix in those cases. + if _SPDX_IDS_TO_VALUES.setdefault(value_as_spdx_id, value) != value: + suffix = hashlib.sha256(value.encode()).hexdigest()[:8] + value_as_spdx_id = f"{value_as_spdx_id}-{suffix}" + assert _SPDX_IDS_TO_VALUES.setdefault(value_as_spdx_id, value) == value + return value_as_spdx_id diff --git a/tests/sbom/sbom-with-pip-removed.json b/tests/sbom/sbom-with-pip-removed.json index b2646f23..0ba2d4c0 100644 --- a/tests/sbom/sbom-with-pip-removed.json +++ b/tests/sbom/sbom-with-pip-removed.json @@ -13,9 +13,9 @@ "packages": [], "relationships": [ { - "relatedSpdxElement": "SPDXRef-FILE-Modules-expat-COPYING-497fb0c3", + "relatedSpdxElement": "SPDXRef-FILE-Modules-expat-COPYING", "relationshipType": "CONTAINS", - "spdxElementId": "SPDXRef-PACKAGE-expat-83b93528" + "spdxElementId": "SPDXRef-PACKAGE-expat" } ] } diff --git a/tests/sbom/sbom-with-pip.json b/tests/sbom/sbom-with-pip.json index d2ee1c6f..e758c182 100644 --- a/tests/sbom/sbom-with-pip.json +++ b/tests/sbom/sbom-with-pip.json @@ -12,7 +12,7 @@ "files": [], "packages": [ { - "SPDXID": "SPDXRef-PACKAGE-pip-ced959c1", + "SPDXID": "SPDXRef-PACKAGE-pip", "name": "pip", "versionInfo": "24.0", "licenseConcluded": "MIT", @@ -38,19 +38,19 @@ ], "relationships": [ { - "relatedSpdxElement": "SPDXRef-FILE-Modules-expat-COPYING-497fb0c3", + "relatedSpdxElement": "SPDXRef-FILE-Modules-expat-COPYING", "relationshipType": "CONTAINS", - "spdxElementId": "SPDXRef-PACKAGE-expat-83b93528" + "spdxElementId": "SPDXRef-PACKAGE-expat" }, { - "relatedSpdxElement": "SPDXRef-PACKAGE-urllib3-b7a198af", + "relatedSpdxElement": "SPDXRef-PACKAGE-urllib3", "relationshipType": "DEPENDS_ON", - "spdxElementId": "SPDXRef-PACKAGE-pip-ced959c1" + "spdxElementId": "SPDXRef-PACKAGE-pip" }, { - "relatedSpdxElement": "SPDXRef-PACKAGE-pip-ced959c1", + "relatedSpdxElement": "SPDXRef-PACKAGE-pip", "relationshipType": "DEPENDS_ON", - "spdxElementId": "SPDXRef-PACKAGE-cpython-608f998c" + "spdxElementId": "SPDXRef-PACKAGE-cpython" } ] } diff --git a/tests/test_sbom.py b/tests/test_sbom.py index 8e7713dc..db2f59af 100644 --- a/tests/test_sbom.py +++ b/tests/test_sbom.py @@ -14,11 +14,11 @@ @pytest.mark.parametrize( ["value", "expected"], [ - ("abc", "abc-ba7816bf"), - ("def", "def-cb8379ac"), - ("SPDXRef-PACKAGE-pip", "SPDXRef-PACKAGE-pip-ced959c1"), - ("SPDXRef-PACKAGE-cpython", "SPDXRef-PACKAGE-cpython-79ab18d2"), - ("SPDXRef-PACKAGE-urllib3", "SPDXRef-PACKAGE-urllib3-b8ab4751"), + ("abc", "abc"), + ("path/name", "path-name"), + ("SPDXRef-PACKAGE-pip", "SPDXRef-PACKAGE-pip"), + ("SPDXRef-PACKAGE-cpython", "SPDXRef-PACKAGE-cpython"), + ("SPDXRef-PACKAGE-urllib3", "SPDXRef-PACKAGE-urllib3"), ], ) def test_spdx_id(value: str, expected: str) -> None: