diff --git a/src/debsbom/generate/cdx.py b/src/debsbom/generate/cdx.py index fe37486..ed47ebf 100644 --- a/src/debsbom/generate/cdx.py +++ b/src/debsbom/generate/cdx.py @@ -29,6 +29,18 @@ logger = logging.getLogger(__name__) +def make_supplier_from_str(supplier: str) -> cdx_contact.OrganizationalEntity | None: + match = SUPPLIER_PATTERN.match(supplier) + if match: + supplier = cdx_contact.OrganizationalEntity(name=match["supplier_name"].strip()) + supplier_email = match["supplier_email"] + if supplier_email: + supplier.contacts = [cdx_contact.OrganizationalContact(email=supplier_email)] + else: + supplier = None + return supplier + + def cdx_package_repr( package: Package, refs: dict[str, cdx_bom_ref.BomRef], vendor: str = "debian" ) -> cdx_component.Component | None: @@ -45,15 +57,10 @@ def cdx_package_repr( ref = Reference.make_from_pkg(package).as_str(SBOMType.CycloneDX) refs[ref] = cdx_bom_ref.BomRef(package.purl().to_string()) - match = SUPPLIER_PATTERN.match(package.maintainer or "") - if match: - supplier = cdx_contact.OrganizationalEntity(name=match["supplier_name"].strip()) - supplier_email = match["supplier_email"] - if supplier_email: - supplier.contacts = [cdx_contact.OrganizationalContact(email=supplier_email)] - else: - supplier = None + supplier = make_supplier_from_str(package.maintainer or "") + if not supplier: logger.warning(f"no supplier for {package}") + entry = cdx_component.Component( name=package.name, type=cdx_component.ComponentType.LIBRARY, @@ -116,15 +123,10 @@ def make_distro_component( ) -> cdx_component.Component: distro_bom_ref = CDX_REF_PREFIX + distro_name - if distro_supplier: - supplier = cdx_contact.OrganizationalEntity(name=distro_supplier) - else: - supplier = None - distro_component = cdx_component.Component( type=cdx_component.ComponentType.OPERATING_SYSTEM, bom_ref=distro_bom_ref, - supplier=supplier, + supplier=make_supplier_from_str(distro_supplier or ""), name=distro_name, version=distro_version, ) diff --git a/tests/test_generation.py b/tests/test_generation.py index 59ca656..5d54c90 100644 --- a/tests/test_generation.py +++ b/tests/test_generation.py @@ -52,6 +52,7 @@ def setup_sbom_generator( timestamp: datetime | None = None, with_licenses: bool = False, sbom_types: list[SBOMType] = list(SBOMType), + distro_supplier: str | None = None, ) -> Debsbom: url = urlparse("http://example.org") if uuid is None: @@ -62,6 +63,7 @@ def setup_sbom_generator( return DebsbomLegacyProxy( distro_name="pytest-distro", distro_arch="amd64", + distro_supplier=distro_supplier, sbom_types=sbom_types, root=str(test_root), spdx_namespace=url, @@ -531,3 +533,22 @@ def test_pre_depends(tmpdir, sbom_generator): ], "ref": "pkg:deb/debian/test-pre-depends@1.0.0-1?arch=amd64", } in dependencies + + +def test_distro_supplier(tmpdir, sbom_generator): + _cyclonedx = pytest.importorskip("cyclonedx") + + # only cyclonedx splits the supplier into multiple fields + dbom = sbom_generator( + "tests/root/tree", + sbom_types=[SBOMType.CycloneDX], + distro_supplier="Test ", + ) + outdir = Path(tmpdir) + dbom.generate(str(outdir / "sbom"), validate=True) + with open(outdir / "sbom.cdx.json") as file: + cdx_json = json.loads(file.read()) + + distro_supplier = cdx_json["metadata"]["component"]["supplier"] + assert distro_supplier["name"] == "Test" + assert any([c["email"] == "test@example.com" for c in distro_supplier["contact"]])