meta_package_manager.sbom.spdx moduleΒΆ

SPDX 2.3 writer plus the per-package upstream-SBOM merge logic.

Heavy spdx_tools imports are guarded behind a try/except block so this module is importable even when the optional [sbom-offline] extra is not installed; in that case spdx_support is False and the SPDX class is still defined for type-hint compatibility but will not function (every public method depends on the missing imports).

_parse_license_expression and _coerce_spdx_string live here because they both touch spdx_tools types; cyclonedx imports the former for its own license normalization, which is one-way and acyclic.

class meta_package_manager.sbom.spdx.SPDX(export_format=ExportFormat.JSON)[source]ΒΆ

Bases: SBOM

Generates an SPDX document from a list of packages.

SPDX 2.3 specifications.

Defaults to JSON export format.

DOC_ID = 'SPDXRef-DOCUMENT'ΒΆ

Document root ID.

document: DocumentΒΆ
seen_ids: set[str]ΒΆ
name_index: dict[tuple[str, str], str]ΒΆ
pending_relationships: list[tuple[str, str, str, Any]]ΒΆ
merged_docs: dict[str, str]ΒΆ
classmethod normalize_spdx_id(value)[source]ΒΆ

SPDX IDs must only contain letters, numbers, . and -.

Return type:

str

init_doc()[source]ΒΆ

SPDX document metadata specifications.

Return type:

None

add_package(manager, package, metadata=PackageMetadata(download_url=None, homepage=None, vcs_url=None, issue_tracker_url=None, distribution_url=None, license_declared=None, license_concluded=None, copyright_text=None, supplier=None, originator=None, description=None, summary=None, cpe=None, dependencies=(), checksums=(), files=(), files_analyzed=False, install_date=None, build_date=None, release_date=None, external_sbom_path=None, extra_purls=(), extras={}))[source]ΒΆ

SPDX package metadata specifications.

Return type:

None

all_purls()[source]ΒΆ

Yield every inventory package purl in insertion order.

Only the directly-installed packages carry a purl in purl_index; transitive packages spliced in from merged upstream SBOMs are not queried for vulnerabilities (their own upstream document already carries that provenance, and they are not what the user installed).

Return type:

Iterator[str]

finalize()[source]ΒΆ

Emit pending dependency relationships and vulnerability refs.

Walks the queue built by add_package() and emits each relationship only when both ends resolve to packages we actually included in the document. Dangling references (the target package is not installed) are dropped silently: the SBOM only describes what is on the system, not what could be.

Then attaches any vulnerability data bound via attach_vulnerabilities(). SPDX 2.3 has no first-class vulnerability section, so each advisory becomes a SECURITY-category ExternalPackageRef of type advisory on the affected package, pointing at the advisory URL.

Return type:

None

stats()[source]ΒΆ

Extend the base stats with SPDX-specific counters.

Adds the number of upstream documents merged into the aggregate, the count of transitive packages those upstream documents contributed (over and above the inventory pass), and the total relationship count partitioned into dependency vs descriptive edges. packages_total from the base reports inventory packages only; packages_in_document here is the full count after merge, which is what consumers of the file actually see.

Return type:

dict[str, object]

export()[source]ΒΆ

Similar to spdx_tools.spdx.writer.write_anything.write_file but write directly to provided stream instead of file path.

Return type:

str