Skip to content

Instantly share code, notes, and snippets.

@pombredanne
Created October 20, 2025 16:33
Show Gist options
  • Select an option

  • Save pombredanne/144854016e1141714dfd639ad71ad3a0 to your computer and use it in GitHub Desktop.

Select an option

Save pombredanne/144854016e1141714dfd639ad71ad3a0 to your computer and use it in GitHub Desktop.
def to_spdx(project, version=spdx.SPDX_SPEC_VERSION_2_3, include_files=False, _fake_test_uuid=None):
"""
Generate output for the provided ``project`` in SPDX document format.
The output file is created in the ``project`` "output/" directory.
Return the path of the generated output file.
"""
if version not in [spdx.SPDX_SPEC_VERSION_2_2, spdx.SPDX_SPEC_VERSION_2_3]:
raise ValueError(f"SPDX {version} is not supported.")
if _fake_test_uuid:
project_uuid = _fake_test_uuid
else:
project_uuid = project.uuid
output_file = project.get_output_file_path("results", "spdx.json")
document_spdx_id = f"SPDXRef-DOCUMENT-{project_uuid}"
discoveredpackage_qs = get_queryset(project, "discoveredpackage")
discovereddependency_qs = get_queryset(project, "discovereddependency")
packages_as_spdx = []
license_expressions = []
relationships = []
project_inputs_as_spdx_packages = get_inputs_as_spdx_packages(project)
if project_inputs_as_spdx_packages:
packages_as_spdx.extend(project_inputs_as_spdx_packages)
# Use the Project's input as the root element that the SPDX document describes.
# This ensures "documentDescribes" points only to the main subject of the SBOM,
# not to every dependency or file in the project.
# See https://github.com/spdx/spdx-spec/issues/395 and
# https://github.com/aboutcode-org/scancode.io/issues/564#issuecomment-3269296563
# for detailed context.
if len(project_inputs_as_spdx_packages) == 1:
describe_spdx_id = project_inputs_as_spdx_packages[0].spdx_id
# Fallback to the Project as the SPDX root element for the "documentDescribes",
# if more than one input, or if no inputs, are available.
else:
project_as_root_package = spdx.Package(
spdx_id=f"SPDXRef-scancodeio-project-{project_uuid}",
name=project.name,
files_analyzed=True,
)
packages_as_spdx.append(project_as_root_package)
describe_spdx_id = project_as_root_package.spdx_id
for package in discoveredpackage_qs:
spdx_package = package.as_spdx()
packages_as_spdx.append(spdx_package)
if license_expression := package.declared_license_expression:
license_expressions.append(license_expression)
spdx_relationship = spdx.Relationship(
spdx_id=describe_spdx_id,
related_spdx_id=spdx_package.spdx_id,
relationship="DEPENDS_ON",
)
relationships.append(spdx_relationship)
for dependency in discovereddependency_qs:
spdx_relationship = get_dependency_as_spdx_relationship(
dependency,
document_spdx_id,
packages_as_spdx,
)
relationships.append(spdx_relationship)
files_as_spdx = []
if include_files:
files_as_spdx = [
resource.as_spdx()
for resource in get_queryset(project, "codebaseresource").files()
]
document = spdx.Document(
version=version,
spdx_id=document_spdx_id,
name=f"scancodeio_{project.name}",
namespace=f"https://scancode.io/spdxdocs/{project_uuid}",
describes=[describe_spdx_id],
creation_info=spdx.CreationInfo(tool=f"ScanCode.io-{scancodeio_version}"),
packages=packages_as_spdx,
files=files_as_spdx,
extracted_licenses=_get_spdx_extracted_licenses(license_expressions),
relationships=relationships,
comment=SCAN_NOTICE,
)
with output_file.open("w") as file:
file.write(document.as_json())
return output_file
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment