spdx_tools.spdx.validation.spdx_id_validators

 1# SPDX-FileCopyrightText: 2022 spdx contributors
 2#
 3# SPDX-License-Identifier: Apache-2.0
 4
 5import re
 6
 7from beartype.typing import List
 8
 9from spdx_tools.spdx.document_utils import get_contained_spdx_element_ids
10from spdx_tools.spdx.model import Document, File
11
12
13def is_valid_internal_spdx_id(spdx_id: str) -> bool:
14    return bool(re.match(r"^SPDXRef-[\da-zA-Z.-]+$", spdx_id))
15
16
17def is_valid_external_doc_ref_id(external_ref_id: str) -> bool:
18    return bool(re.match(r"^DocumentRef-[\da-zA-Z.+-]+$", external_ref_id))
19
20
21def is_spdx_id_present_in_files(spdx_id: str, files: List[File]) -> bool:
22    return spdx_id in [file.spdx_id for file in files]
23
24
25def is_spdx_id_present_in_document(spdx_id: str, document: Document) -> bool:
26    all_spdx_ids_in_document: List[str] = get_list_of_all_spdx_ids(document)
27
28    return spdx_id in all_spdx_ids_in_document
29
30
31def get_list_of_all_spdx_ids(document: Document) -> List[str]:
32    all_spdx_ids_in_document: List[str] = [document.creation_info.spdx_id]
33    all_spdx_ids_in_document.extend(get_contained_spdx_element_ids(document))
34
35    return all_spdx_ids_in_document
36
37
38def is_external_doc_ref_present_in_document(external_ref_id: str, document: Document) -> bool:
39    all_external_doc_ref_ids_in_document = [
40        external_doc_ref.document_ref_id for external_doc_ref in document.creation_info.external_document_refs
41    ]
42
43    return external_ref_id in all_external_doc_ref_ids_in_document
44
45
46def validate_spdx_id(
47    spdx_id: str, document: Document, check_document: bool = False, check_files: bool = False
48) -> List[str]:
49    """Test that the given spdx_id (and a potential DocumentRef to an external document) is valid
50    and, if it is a reference, actually exists in the document. Optionally checks files or the whole document
51    for the existence of the spdx_id (i.e. if it is used as a reference). Returns a list of validation messages."""
52
53    validation_messages: List[str] = []
54    split_id: List[str] = spdx_id.split(":")
55
56    # # # invalid case # # #
57    if len(split_id) > 2:
58        return [
59            f"spdx_id must not contain more than one colon in order to separate the external document reference id "
60            f"from the internal SPDX id, but is: {spdx_id}"
61        ]
62
63    # # # case with external document ref prefix # # #
64    if len(split_id) == 2:
65        if not is_valid_external_doc_ref_id(split_id[0]):
66            validation_messages.append(
67                f'the external document reference part of spdx_id must only contain letters, numbers, ".", "-" and '
68                f'"+" and must begin with "DocumentRef-", but is: {split_id[0]}'
69            )
70        if not is_valid_internal_spdx_id(split_id[1]):
71            validation_messages.append(
72                f'the internal SPDX id part of spdx_id must only contain letters, numbers, "." and "-" and must begin '
73                f'with "SPDXRef-", but is: {split_id[1]}'
74            )
75        if not is_external_doc_ref_present_in_document(split_id[0], document):
76            validation_messages.append(
77                f'did not find the external document reference "{split_id[0]}" in the SPDX document'
78            )
79
80        return validation_messages
81
82    # # # "normal" case # # #
83    if not is_valid_internal_spdx_id(spdx_id):
84        validation_messages.append(
85            f'spdx_id must only contain letters, numbers, "." and "-" and must begin with "SPDXRef-", but is: '
86            f"{spdx_id}"
87        )
88
89    if check_document:
90        if not is_spdx_id_present_in_document(spdx_id, document):
91            validation_messages.append(f'did not find the referenced spdx_id "{spdx_id}" in the SPDX document')
92
93    if check_files:
94        if not is_spdx_id_present_in_files(spdx_id, document.files):
95            validation_messages.append(
96                f'did not find the referenced spdx_id "{spdx_id}" in the SPDX document\'s files'
97            )
98
99    return validation_messages
def is_valid_internal_spdx_id(spdx_id: str) -> bool:
14def is_valid_internal_spdx_id(spdx_id: str) -> bool:
15    return bool(re.match(r"^SPDXRef-[\da-zA-Z.-]+$", spdx_id))
def is_valid_external_doc_ref_id(external_ref_id: str) -> bool:
18def is_valid_external_doc_ref_id(external_ref_id: str) -> bool:
19    return bool(re.match(r"^DocumentRef-[\da-zA-Z.+-]+$", external_ref_id))
def is_spdx_id_present_in_files(spdx_id: str, files: list[spdx_tools.spdx.model.file.File]) -> bool:
22def is_spdx_id_present_in_files(spdx_id: str, files: List[File]) -> bool:
23    return spdx_id in [file.spdx_id for file in files]
def is_spdx_id_present_in_document(spdx_id: str, document: spdx_tools.spdx.model.document.Document) -> bool:
26def is_spdx_id_present_in_document(spdx_id: str, document: Document) -> bool:
27    all_spdx_ids_in_document: List[str] = get_list_of_all_spdx_ids(document)
28
29    return spdx_id in all_spdx_ids_in_document
def get_list_of_all_spdx_ids(document: spdx_tools.spdx.model.document.Document) -> list[str]:
32def get_list_of_all_spdx_ids(document: Document) -> List[str]:
33    all_spdx_ids_in_document: List[str] = [document.creation_info.spdx_id]
34    all_spdx_ids_in_document.extend(get_contained_spdx_element_ids(document))
35
36    return all_spdx_ids_in_document
def is_external_doc_ref_present_in_document( external_ref_id: str, document: spdx_tools.spdx.model.document.Document) -> bool:
39def is_external_doc_ref_present_in_document(external_ref_id: str, document: Document) -> bool:
40    all_external_doc_ref_ids_in_document = [
41        external_doc_ref.document_ref_id for external_doc_ref in document.creation_info.external_document_refs
42    ]
43
44    return external_ref_id in all_external_doc_ref_ids_in_document
def validate_spdx_id( spdx_id: str, document: spdx_tools.spdx.model.document.Document, check_document: bool = False, check_files: bool = False) -> list[str]:
 47def validate_spdx_id(
 48    spdx_id: str, document: Document, check_document: bool = False, check_files: bool = False
 49) -> List[str]:
 50    """Test that the given spdx_id (and a potential DocumentRef to an external document) is valid
 51    and, if it is a reference, actually exists in the document. Optionally checks files or the whole document
 52    for the existence of the spdx_id (i.e. if it is used as a reference). Returns a list of validation messages."""
 53
 54    validation_messages: List[str] = []
 55    split_id: List[str] = spdx_id.split(":")
 56
 57    # # # invalid case # # #
 58    if len(split_id) > 2:
 59        return [
 60            f"spdx_id must not contain more than one colon in order to separate the external document reference id "
 61            f"from the internal SPDX id, but is: {spdx_id}"
 62        ]
 63
 64    # # # case with external document ref prefix # # #
 65    if len(split_id) == 2:
 66        if not is_valid_external_doc_ref_id(split_id[0]):
 67            validation_messages.append(
 68                f'the external document reference part of spdx_id must only contain letters, numbers, ".", "-" and '
 69                f'"+" and must begin with "DocumentRef-", but is: {split_id[0]}'
 70            )
 71        if not is_valid_internal_spdx_id(split_id[1]):
 72            validation_messages.append(
 73                f'the internal SPDX id part of spdx_id must only contain letters, numbers, "." and "-" and must begin '
 74                f'with "SPDXRef-", but is: {split_id[1]}'
 75            )
 76        if not is_external_doc_ref_present_in_document(split_id[0], document):
 77            validation_messages.append(
 78                f'did not find the external document reference "{split_id[0]}" in the SPDX document'
 79            )
 80
 81        return validation_messages
 82
 83    # # # "normal" case # # #
 84    if not is_valid_internal_spdx_id(spdx_id):
 85        validation_messages.append(
 86            f'spdx_id must only contain letters, numbers, "." and "-" and must begin with "SPDXRef-", but is: '
 87            f"{spdx_id}"
 88        )
 89
 90    if check_document:
 91        if not is_spdx_id_present_in_document(spdx_id, document):
 92            validation_messages.append(f'did not find the referenced spdx_id "{spdx_id}" in the SPDX document')
 93
 94    if check_files:
 95        if not is_spdx_id_present_in_files(spdx_id, document.files):
 96            validation_messages.append(
 97                f'did not find the referenced spdx_id "{spdx_id}" in the SPDX document\'s files'
 98            )
 99
100    return validation_messages

Test that the given spdx_id (and a potential DocumentRef to an external document) is valid and, if it is a reference, actually exists in the document. Optionally checks files or the whole document for the existence of the spdx_id (i.e. if it is used as a reference). Returns a list of validation messages.