Module continuous_delivery_scripts.spdx_report.spdx_document
Definition of an SPDX Document.
Expand source code
#
# Copyright (C) 2020-2025 Arm Limited or its affiliates and Contributors. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
#
"""Definition of an SPDX Document."""
from pathlib import Path
from spdx.creationinfo import Person, Organization, Tool
from spdx.document import Document, License
from spdx.review import Review
from spdx.version import Version
from typing import List, Optional
from continuous_delivery_scripts.spdx_report.spdx_dependency import DependencySpdxDocumentRef
from continuous_delivery_scripts.spdx_report.spdx_helpers import determine_spdx_value, get_project_namespace
from continuous_delivery_scripts.spdx_report.spdx_package import SpdxPackage, PackageInfo
from continuous_delivery_scripts.utils.configuration import configuration, ConfigurationVariable
from continuous_delivery_scripts.utils.hash_helpers import generate_uuid_based_on_str
from continuous_delivery_scripts.utils.python.package_helpers import PackageMetadata
TOOL_NAME = "mbed-spdx-generator"
class SpdxDocument:
    """SPDX document.
    See https://spdx.org/spdx-specification-21-web-version#h.4d34og8
    """
    def __init__(
        self,
        package_metadata: PackageMetadata,
        other_document_refs: List[DependencySpdxDocumentRef] = list(),
        is_dependency: bool = False,
        document_namespace: Optional[str] = None,
    ):
        """Constructor."""
        self._project_root = Path(configuration.get_value(ConfigurationVariable.PROJECT_ROOT))
        self._project_uuid = str(configuration.get_value(ConfigurationVariable.PROJECT_UUID))
        self._project_config = Path(configuration.get_value(ConfigurationVariable.PROJECT_CONFIG))
        self._project_source = self._project_root.joinpath(configuration.get_value(ConfigurationVariable.SOURCE_DIR))
        self._package_metadata: PackageMetadata = package_metadata
        self._is_dependency: bool = is_dependency
        self._other_document_references: List[DependencySpdxDocumentRef] = other_document_refs
        self._document_namespace = document_namespace
        self._spdx_package: Optional[SpdxPackage] = None
    @property
    def document_name(self) -> str:
        """Gets document name.
        See https://spdx.org/spdx-specification-21-web-version#h.wape5vaqknj2
        Returns:
            corresponding string
        """
        return f"{self.name}-{self.version}"
    @property
    def document_namespace(self) -> str:
        """Gets document namespace.
        See https://spdx.org/spdx-specification-21-web-version#h.1gdfkutofa90
        Returns:
            corresponding string
        """
        if self._document_namespace:
            return self._document_namespace
        return self._generate_namespace()
    def _generate_namespace(self) -> str:
        """Generates a document namespace."""
        if self._is_dependency:
            url_base = "http://spdx.org/spdxdocs"
            uuid = generate_uuid_based_on_str(self.document_name)
            return f"{url_base}/{self.document_name}-{uuid}"
        return get_project_namespace(self._project_config, self.document_name)
    @property
    def name(self) -> str:
        """Gets package's name.
        Returns:
            corresponding string
        """
        return f"{self._package_metadata.name}"
    @property
    def version(self) -> str:
        """Gets package version.
        Returns:
            package version
        """
        return self._package_metadata.version
    @property
    def licence(self) -> str:
        """Gets the project's licence.
        Returns:
            project's licence
        """
        return self._package_metadata.licence
    @property
    def author(self) -> str:
        """Gets the document's author.
        Returns:
            document's author
        """
        return self._package_metadata.author
    @property
    def author_email(self) -> str:
        """Gets the document author's email.
        Returns:
            document author's email
        """
        return self._package_metadata.author_email
    @property
    def organisation(self) -> str:
        """Gets the organisation.
        Returns:
            the organisation in charge
        """
        return str(configuration.get_value(ConfigurationVariable.ORGANISATION))
    @property
    def organisation_email(self) -> str:
        """Gets the organisation's email.
        Returns:
            organisation's email
        """
        return str(configuration.get_value(ConfigurationVariable.ORGANISATION_EMAIL))
    @property
    def tool_name(self) -> str:
        """Gets this generation tool's name.
        Returns:
            this tool's name
        """
        return TOOL_NAME
    @property
    def reviewer(self) -> str:
        """Gets the document's reviewer.
        Returns:
            document's reviewer
        """
        return str(configuration.get_value(ConfigurationVariable.BOT_USERNAME))
    @property
    def reviewer_email(self) -> str:
        """Gets the document reviewer's email.
        Returns:
            document reviewer's email
        """
        return str(configuration.get_value(ConfigurationVariable.BOT_EMAIL))
    @property
    def external_refs(self) -> List[DependencySpdxDocumentRef]:
        """Gets the document external references.
        Returns:
            the list of external references
        """
        return self._other_document_references
    @external_refs.setter
    def external_refs(self, external_refs: List[DependencySpdxDocumentRef]) -> None:
        """Sets the document external references."""
        self._other_document_references = external_refs
    def generate_spdx_package(self) -> SpdxPackage:
        """Generates the SPDX package for this package.
        Returns:
            corresponding SPDX package.
        """
        if not self._spdx_package:
            self._spdx_package = SpdxPackage(
                PackageInfo(
                    metadata=self._package_metadata,
                    root_dir=self._project_root,
                    source_dir=self._project_source,
                    uuid=self._project_uuid,
                ),
                is_dependency=self._is_dependency,
            )
        return self._spdx_package
    def generate_spdx_document(self) -> Document:
        """Generates the SPDX document.
        Example of SPDX document section.
        SPDXVersion: SPDX-2.1
        DataLicense: CC0-1.0
        SPDXID: SPDXRef-DOCUMENT
        DocumentName: mbed-targets
        DocumentNamespace: http://spdx.org/spdxdocs/spdx-v2.1-3c4714e6-a7b1-4574-abb8-861149cbc590
        Creator: Person: Anonymous ()
        Creator: Organization: Anonymous ()
        Creator: Tool: reuse-0.8.0
        Created: 2020-01-20T17:53:41Z
        CreatorComment: <text>
        This document was created automatically using available reuse information consistent with REUSE.
        </text>
        Returns:
            the corresponding document
        """
        doc = Document()
        doc.version = Version(1, 2)
        doc.name = determine_spdx_value(self.document_name)
        doc.namespace = determine_spdx_value(self.document_namespace)
        doc.spdx_id = "SPDXRef-DOCUMENT"
        doc.comment = determine_spdx_value(
            "This document was created automatically using available information from python packages."
        )
        doc.data_license = License.from_identifier("CC0-1.0")
        doc.creation_info.add_creator(Person(self.author, self.author_email))
        if not self._is_dependency:
            doc.creation_info.add_creator(Organization(self.organisation, self.organisation_email))
        doc.creation_info.add_creator(Tool(self.tool_name))
        doc.creation_info.set_created_now()
        if not self._is_dependency:
            review = Review(Person(determine_spdx_value(self.reviewer), determine_spdx_value(self.reviewer_email)))
            review.set_review_date_now()
            doc.add_review(review)
        # FIXME with current tooling and specification, only one package can
        #  be described in a file and hence, all dependencies are described
        #  in separate files. Find out what to do with dependencies when new
        #  tools are released as it is not entirely clear in the specification
        doc.package = self.generate_spdx_package().generate_spdx_package()
        for external_reference in self.external_refs:
            doc.add_ext_document_reference(external_reference.generate_external_reference())
        return doc
Classes
class SpdxDocument (package_metadata: PackageMetadata, other_document_refs: List[DependencySpdxDocumentRef] = [], is_dependency: bool = False, document_namespace: Optional[str] = None)- 
Expand source code
class SpdxDocument: """SPDX document. See https://spdx.org/spdx-specification-21-web-version#h.4d34og8 """ def __init__( self, package_metadata: PackageMetadata, other_document_refs: List[DependencySpdxDocumentRef] = list(), is_dependency: bool = False, document_namespace: Optional[str] = None, ): """Constructor.""" self._project_root = Path(configuration.get_value(ConfigurationVariable.PROJECT_ROOT)) self._project_uuid = str(configuration.get_value(ConfigurationVariable.PROJECT_UUID)) self._project_config = Path(configuration.get_value(ConfigurationVariable.PROJECT_CONFIG)) self._project_source = self._project_root.joinpath(configuration.get_value(ConfigurationVariable.SOURCE_DIR)) self._package_metadata: PackageMetadata = package_metadata self._is_dependency: bool = is_dependency self._other_document_references: List[DependencySpdxDocumentRef] = other_document_refs self._document_namespace = document_namespace self._spdx_package: Optional[SpdxPackage] = None @property def document_name(self) -> str: """Gets document name. See https://spdx.org/spdx-specification-21-web-version#h.wape5vaqknj2 Returns: corresponding string """ return f"{self.name}-{self.version}" @property def document_namespace(self) -> str: """Gets document namespace. See https://spdx.org/spdx-specification-21-web-version#h.1gdfkutofa90 Returns: corresponding string """ if self._document_namespace: return self._document_namespace return self._generate_namespace() def _generate_namespace(self) -> str: """Generates a document namespace.""" if self._is_dependency: url_base = "http://spdx.org/spdxdocs" uuid = generate_uuid_based_on_str(self.document_name) return f"{url_base}/{self.document_name}-{uuid}" return get_project_namespace(self._project_config, self.document_name) @property def name(self) -> str: """Gets package's name. Returns: corresponding string """ return f"{self._package_metadata.name}" @property def version(self) -> str: """Gets package version. Returns: package version """ return self._package_metadata.version @property def licence(self) -> str: """Gets the project's licence. Returns: project's licence """ return self._package_metadata.licence @property def author(self) -> str: """Gets the document's author. Returns: document's author """ return self._package_metadata.author @property def author_email(self) -> str: """Gets the document author's email. Returns: document author's email """ return self._package_metadata.author_email @property def organisation(self) -> str: """Gets the organisation. Returns: the organisation in charge """ return str(configuration.get_value(ConfigurationVariable.ORGANISATION)) @property def organisation_email(self) -> str: """Gets the organisation's email. Returns: organisation's email """ return str(configuration.get_value(ConfigurationVariable.ORGANISATION_EMAIL)) @property def tool_name(self) -> str: """Gets this generation tool's name. Returns: this tool's name """ return TOOL_NAME @property def reviewer(self) -> str: """Gets the document's reviewer. Returns: document's reviewer """ return str(configuration.get_value(ConfigurationVariable.BOT_USERNAME)) @property def reviewer_email(self) -> str: """Gets the document reviewer's email. Returns: document reviewer's email """ return str(configuration.get_value(ConfigurationVariable.BOT_EMAIL)) @property def external_refs(self) -> List[DependencySpdxDocumentRef]: """Gets the document external references. Returns: the list of external references """ return self._other_document_references @external_refs.setter def external_refs(self, external_refs: List[DependencySpdxDocumentRef]) -> None: """Sets the document external references.""" self._other_document_references = external_refs def generate_spdx_package(self) -> SpdxPackage: """Generates the SPDX package for this package. Returns: corresponding SPDX package. """ if not self._spdx_package: self._spdx_package = SpdxPackage( PackageInfo( metadata=self._package_metadata, root_dir=self._project_root, source_dir=self._project_source, uuid=self._project_uuid, ), is_dependency=self._is_dependency, ) return self._spdx_package def generate_spdx_document(self) -> Document: """Generates the SPDX document. Example of SPDX document section. SPDXVersion: SPDX-2.1 DataLicense: CC0-1.0 SPDXID: SPDXRef-DOCUMENT DocumentName: mbed-targets DocumentNamespace: http://spdx.org/spdxdocs/spdx-v2.1-3c4714e6-a7b1-4574-abb8-861149cbc590 Creator: Person: Anonymous () Creator: Organization: Anonymous () Creator: Tool: reuse-0.8.0 Created: 2020-01-20T17:53:41Z CreatorComment: <text> This document was created automatically using available reuse information consistent with REUSE. </text> Returns: the corresponding document """ doc = Document() doc.version = Version(1, 2) doc.name = determine_spdx_value(self.document_name) doc.namespace = determine_spdx_value(self.document_namespace) doc.spdx_id = "SPDXRef-DOCUMENT" doc.comment = determine_spdx_value( "This document was created automatically using available information from python packages." ) doc.data_license = License.from_identifier("CC0-1.0") doc.creation_info.add_creator(Person(self.author, self.author_email)) if not self._is_dependency: doc.creation_info.add_creator(Organization(self.organisation, self.organisation_email)) doc.creation_info.add_creator(Tool(self.tool_name)) doc.creation_info.set_created_now() if not self._is_dependency: review = Review(Person(determine_spdx_value(self.reviewer), determine_spdx_value(self.reviewer_email))) review.set_review_date_now() doc.add_review(review) # FIXME with current tooling and specification, only one package can # be described in a file and hence, all dependencies are described # in separate files. Find out what to do with dependencies when new # tools are released as it is not entirely clear in the specification doc.package = self.generate_spdx_package().generate_spdx_package() for external_reference in self.external_refs: doc.add_ext_document_reference(external_reference.generate_external_reference()) return docInstance variables
- 
Gets the document's author.
Returns
document's author
Expand source code
@property def author(self) -> str: """Gets the document's author. Returns: document's author """ return self._package_metadata.author - 
Gets the document author's email.
Returns
document author's email
Expand source code
@property def author_email(self) -> str: """Gets the document author's email. Returns: document author's email """ return self._package_metadata.author_email var document_name : str- 
Gets document name.
See https://spdx.org/spdx-specification-21-web-version#h.wape5vaqknj2
Returns
corresponding string
Expand source code
@property def document_name(self) -> str: """Gets document name. See https://spdx.org/spdx-specification-21-web-version#h.wape5vaqknj2 Returns: corresponding string """ return f"{self.name}-{self.version}" var document_namespace : str- 
Gets document namespace.
See https://spdx.org/spdx-specification-21-web-version#h.1gdfkutofa90
Returns
corresponding string
Expand source code
@property def document_namespace(self) -> str: """Gets document namespace. See https://spdx.org/spdx-specification-21-web-version#h.1gdfkutofa90 Returns: corresponding string """ if self._document_namespace: return self._document_namespace return self._generate_namespace() var external_refs : List[DependencySpdxDocumentRef]- 
Gets the document external references.
Returns
the list of external references
Expand source code
@property def external_refs(self) -> List[DependencySpdxDocumentRef]: """Gets the document external references. Returns: the list of external references """ return self._other_document_references var licence : str- 
Gets the project's licence.
Returns
project's licence
Expand source code
@property def licence(self) -> str: """Gets the project's licence. Returns: project's licence """ return self._package_metadata.licence var name : str- 
Gets package's name.
Returns
corresponding string
Expand source code
@property def name(self) -> str: """Gets package's name. Returns: corresponding string """ return f"{self._package_metadata.name}" var organisation : str- 
Gets the organisation.
Returns
the organisation in charge
Expand source code
@property def organisation(self) -> str: """Gets the organisation. Returns: the organisation in charge """ return str(configuration.get_value(ConfigurationVariable.ORGANISATION)) var organisation_email : str- 
Gets the organisation's email.
Returns
organisation's email
Expand source code
@property def organisation_email(self) -> str: """Gets the organisation's email. Returns: organisation's email """ return str(configuration.get_value(ConfigurationVariable.ORGANISATION_EMAIL)) var reviewer : str- 
Gets the document's reviewer.
Returns
document's reviewer
Expand source code
@property def reviewer(self) -> str: """Gets the document's reviewer. Returns: document's reviewer """ return str(configuration.get_value(ConfigurationVariable.BOT_USERNAME)) var reviewer_email : str- 
Gets the document reviewer's email.
Returns
document reviewer's email
Expand source code
@property def reviewer_email(self) -> str: """Gets the document reviewer's email. Returns: document reviewer's email """ return str(configuration.get_value(ConfigurationVariable.BOT_EMAIL)) var tool_name : str- 
Gets this generation tool's name.
Returns
this tool's name
Expand source code
@property def tool_name(self) -> str: """Gets this generation tool's name. Returns: this tool's name """ return TOOL_NAME var version : str- 
Gets package version.
Returns
package version
Expand source code
@property def version(self) -> str: """Gets package version. Returns: package version """ return self._package_metadata.version 
Methods
def generate_spdx_document(self) ‑> spdx.document.Document- 
Generates the SPDX document.
Example of SPDX document section. SPDXVersion: SPDX-2.1 DataLicense: CC0-1.0 SPDXID: SPDXRef-DOCUMENT DocumentName: mbed-targets DocumentNamespace: http://spdx.org/spdxdocs/spdx-v2.1-3c4714e6-a7b1-4574-abb8-861149cbc590 Creator: Person: Anonymous () Creator: Organization: Anonymous () Creator: Tool: reuse-0.8.0 Created: 2020-01-20T17:53:41Z CreatorComment:
This document was created automatically using available reuse information consistent with REUSE. Returns
the corresponding document
Expand source code
def generate_spdx_document(self) -> Document: """Generates the SPDX document. Example of SPDX document section. SPDXVersion: SPDX-2.1 DataLicense: CC0-1.0 SPDXID: SPDXRef-DOCUMENT DocumentName: mbed-targets DocumentNamespace: http://spdx.org/spdxdocs/spdx-v2.1-3c4714e6-a7b1-4574-abb8-861149cbc590 Creator: Person: Anonymous () Creator: Organization: Anonymous () Creator: Tool: reuse-0.8.0 Created: 2020-01-20T17:53:41Z CreatorComment: <text> This document was created automatically using available reuse information consistent with REUSE. </text> Returns: the corresponding document """ doc = Document() doc.version = Version(1, 2) doc.name = determine_spdx_value(self.document_name) doc.namespace = determine_spdx_value(self.document_namespace) doc.spdx_id = "SPDXRef-DOCUMENT" doc.comment = determine_spdx_value( "This document was created automatically using available information from python packages." ) doc.data_license = License.from_identifier("CC0-1.0") doc.creation_info.add_creator(Person(self.author, self.author_email)) if not self._is_dependency: doc.creation_info.add_creator(Organization(self.organisation, self.organisation_email)) doc.creation_info.add_creator(Tool(self.tool_name)) doc.creation_info.set_created_now() if not self._is_dependency: review = Review(Person(determine_spdx_value(self.reviewer), determine_spdx_value(self.reviewer_email))) review.set_review_date_now() doc.add_review(review) # FIXME with current tooling and specification, only one package can # be described in a file and hence, all dependencies are described # in separate files. Find out what to do with dependencies when new # tools are released as it is not entirely clear in the specification doc.package = self.generate_spdx_package().generate_spdx_package() for external_reference in self.external_refs: doc.add_ext_document_reference(external_reference.generate_external_reference()) return doc def generate_spdx_package(self) ‑> SpdxPackage- 
Generates the SPDX package for this package.
Returns
corresponding SPDX package.
Expand source code
def generate_spdx_package(self) -> SpdxPackage: """Generates the SPDX package for this package. Returns: corresponding SPDX package. """ if not self._spdx_package: self._spdx_package = SpdxPackage( PackageInfo( metadata=self._package_metadata, root_dir=self._project_root, source_dir=self._project_source, uuid=self._project_uuid, ), is_dependency=self._is_dependency, ) return self._spdx_package 
 -