spdx_tools.spdx.validation.document_validator
1# SPDX-FileCopyrightText: 2022 spdx contributors 2# 3# SPDX-License-Identifier: Apache-2.0 4from beartype.typing import List 5 6from spdx_tools.spdx.model import Document, RelationshipType 7from spdx_tools.spdx.model.relationship_filters import filter_by_type_and_origin, filter_by_type_and_target 8from spdx_tools.spdx.validation.annotation_validator import validate_annotations 9from spdx_tools.spdx.validation.creation_info_validator import validate_creation_info 10from spdx_tools.spdx.validation.extracted_licensing_info_validator import validate_extracted_licensing_infos 11from spdx_tools.spdx.validation.file_validator import validate_files 12from spdx_tools.spdx.validation.package_validator import validate_packages 13from spdx_tools.spdx.validation.relationship_validator import validate_relationships 14from spdx_tools.spdx.validation.snippet_validator import validate_snippets 15from spdx_tools.spdx.validation.spdx_id_validators import get_list_of_all_spdx_ids 16from spdx_tools.spdx.validation.validation_message import SpdxElementType, ValidationContext, ValidationMessage 17 18 19def validate_full_spdx_document(document: Document, spdx_version: str = None) -> List[ValidationMessage]: 20 validation_messages: List[ValidationMessage] = [] 21 22 # SPDX version validation has to happen here because subsequent validators rely on it 23 document_version: str = document.creation_info.spdx_version 24 context = ValidationContext(spdx_id=document.creation_info.spdx_id, element_type=SpdxElementType.DOCUMENT) 25 if not spdx_version: 26 spdx_version = document_version 27 28 if document_version not in ["SPDX-2.2", "SPDX-2.3"]: 29 validation_messages.append( 30 ValidationMessage( 31 f'only SPDX versions "SPDX-2.2" and "SPDX-2.3" are supported, but the document\'s spdx_version is: ' 32 f"{document_version}", 33 context, 34 ) 35 ) 36 elif spdx_version != document_version: 37 validation_messages.append( 38 ValidationMessage( 39 f"provided SPDX version {spdx_version} does not match " 40 f"the document's SPDX version {document_version}", 41 context, 42 ) 43 ) 44 45 if validation_messages: 46 validation_messages.append( 47 ValidationMessage( 48 "There are issues concerning the SPDX version of the document. " 49 "As subsequent validation relies on the correct version, " 50 "the validation process has been cancelled.", 51 context, 52 ) 53 ) 54 return validation_messages 55 56 validation_messages.extend(validate_creation_info(document.creation_info, spdx_version)) 57 validation_messages.extend(validate_packages(document.packages, spdx_version, document)) 58 validation_messages.extend(validate_files(document.files, spdx_version, document)) 59 validation_messages.extend(validate_snippets(document.snippets, spdx_version, document)) 60 validation_messages.extend(validate_annotations(document.annotations, document)) 61 validation_messages.extend(validate_relationships(document.relationships, spdx_version, document)) 62 validation_messages.extend(validate_extracted_licensing_infos(document.extracted_licensing_info)) 63 64 document_id = document.creation_info.spdx_id 65 document_describes_relationships = filter_by_type_and_origin( 66 document.relationships, RelationshipType.DESCRIBES, document_id 67 ) 68 described_by_document_relationships = filter_by_type_and_target( 69 document.relationships, RelationshipType.DESCRIBED_BY, document_id 70 ) 71 72 only_a_single_package = len(document.packages) == 1 and not document.files and not document.snippets 73 if not only_a_single_package and not document_describes_relationships + described_by_document_relationships: 74 validation_messages.append( 75 ValidationMessage( 76 f'there must be at least one relationship "{document_id} DESCRIBES ..." or "... DESCRIBED_BY ' 77 f'{document_id}" when there is not only a single package present', 78 ValidationContext(spdx_id=document_id, element_type=SpdxElementType.DOCUMENT), 79 ) 80 ) 81 82 all_spdx_ids: List[str] = get_list_of_all_spdx_ids(document) 83 auxiliary_set = set() 84 duplicated_spdx_ids = set( 85 spdx_id for spdx_id in all_spdx_ids if spdx_id in auxiliary_set or auxiliary_set.add(spdx_id) 86 ) 87 88 if duplicated_spdx_ids: 89 validation_messages.append( 90 ValidationMessage( 91 f"every spdx_id must be unique within the document, but found the following duplicates: " 92 f"{sorted(duplicated_spdx_ids)}", 93 context, 94 ) 95 ) 96 97 return validation_messages
def
validate_full_spdx_document( document: spdx_tools.spdx.model.document.Document, spdx_version: str = None) -> list[spdx_tools.spdx.validation.validation_message.ValidationMessage]:
20def validate_full_spdx_document(document: Document, spdx_version: str = None) -> List[ValidationMessage]: 21 validation_messages: List[ValidationMessage] = [] 22 23 # SPDX version validation has to happen here because subsequent validators rely on it 24 document_version: str = document.creation_info.spdx_version 25 context = ValidationContext(spdx_id=document.creation_info.spdx_id, element_type=SpdxElementType.DOCUMENT) 26 if not spdx_version: 27 spdx_version = document_version 28 29 if document_version not in ["SPDX-2.2", "SPDX-2.3"]: 30 validation_messages.append( 31 ValidationMessage( 32 f'only SPDX versions "SPDX-2.2" and "SPDX-2.3" are supported, but the document\'s spdx_version is: ' 33 f"{document_version}", 34 context, 35 ) 36 ) 37 elif spdx_version != document_version: 38 validation_messages.append( 39 ValidationMessage( 40 f"provided SPDX version {spdx_version} does not match " 41 f"the document's SPDX version {document_version}", 42 context, 43 ) 44 ) 45 46 if validation_messages: 47 validation_messages.append( 48 ValidationMessage( 49 "There are issues concerning the SPDX version of the document. " 50 "As subsequent validation relies on the correct version, " 51 "the validation process has been cancelled.", 52 context, 53 ) 54 ) 55 return validation_messages 56 57 validation_messages.extend(validate_creation_info(document.creation_info, spdx_version)) 58 validation_messages.extend(validate_packages(document.packages, spdx_version, document)) 59 validation_messages.extend(validate_files(document.files, spdx_version, document)) 60 validation_messages.extend(validate_snippets(document.snippets, spdx_version, document)) 61 validation_messages.extend(validate_annotations(document.annotations, document)) 62 validation_messages.extend(validate_relationships(document.relationships, spdx_version, document)) 63 validation_messages.extend(validate_extracted_licensing_infos(document.extracted_licensing_info)) 64 65 document_id = document.creation_info.spdx_id 66 document_describes_relationships = filter_by_type_and_origin( 67 document.relationships, RelationshipType.DESCRIBES, document_id 68 ) 69 described_by_document_relationships = filter_by_type_and_target( 70 document.relationships, RelationshipType.DESCRIBED_BY, document_id 71 ) 72 73 only_a_single_package = len(document.packages) == 1 and not document.files and not document.snippets 74 if not only_a_single_package and not document_describes_relationships + described_by_document_relationships: 75 validation_messages.append( 76 ValidationMessage( 77 f'there must be at least one relationship "{document_id} DESCRIBES ..." or "... DESCRIBED_BY ' 78 f'{document_id}" when there is not only a single package present', 79 ValidationContext(spdx_id=document_id, element_type=SpdxElementType.DOCUMENT), 80 ) 81 ) 82 83 all_spdx_ids: List[str] = get_list_of_all_spdx_ids(document) 84 auxiliary_set = set() 85 duplicated_spdx_ids = set( 86 spdx_id for spdx_id in all_spdx_ids if spdx_id in auxiliary_set or auxiliary_set.add(spdx_id) 87 ) 88 89 if duplicated_spdx_ids: 90 validation_messages.append( 91 ValidationMessage( 92 f"every spdx_id must be unique within the document, but found the following duplicates: " 93 f"{sorted(duplicated_spdx_ids)}", 94 context, 95 ) 96 ) 97 98 return validation_messages