spdx_tools.spdx.validation.package_validator
1# SPDX-FileCopyrightText: 2022 spdx contributors 2# 3# SPDX-License-Identifier: Apache-2.0 4 5from beartype.typing import List, Optional 6 7from spdx_tools.spdx.model import Document, File, Package, Relationship, RelationshipType 8from spdx_tools.spdx.model.relationship_filters import filter_by_type_and_origin, filter_by_type_and_target 9from spdx_tools.spdx.spdx_element_utils import get_element_type_from_spdx_id 10from spdx_tools.spdx.validation.checksum_validator import validate_checksums 11from spdx_tools.spdx.validation.external_package_ref_validator import validate_external_package_refs 12from spdx_tools.spdx.validation.license_expression_validator import ( 13 validate_license_expression, 14 validate_license_expressions, 15) 16from spdx_tools.spdx.validation.package_verification_code_validator import validate_verification_code 17from spdx_tools.spdx.validation.spdx_id_validators import validate_spdx_id 18from spdx_tools.spdx.validation.uri_validators import validate_download_location, validate_url 19from spdx_tools.spdx.validation.validation_message import SpdxElementType, ValidationContext, ValidationMessage 20 21 22def validate_packages( 23 packages: List[Package], spdx_version: str, document: Optional[Document] = None 24) -> List[ValidationMessage]: 25 validation_messages: List[ValidationMessage] = [] 26 if document: 27 for package in packages: 28 validation_messages.extend(validate_package_within_document(package, spdx_version, document)) 29 else: 30 for package in packages: 31 validation_messages.extend(validate_package(package, spdx_version)) 32 33 return validation_messages 34 35 36def validate_package_within_document( 37 package: Package, spdx_version: str, document: Document 38) -> List[ValidationMessage]: 39 validation_messages: List[ValidationMessage] = [] 40 context = ValidationContext( 41 spdx_id=package.spdx_id, 42 parent_id=document.creation_info.spdx_id, 43 element_type=SpdxElementType.PACKAGE, 44 full_element=package, 45 ) 46 47 for message in validate_spdx_id(package.spdx_id, document): 48 validation_messages.append(ValidationMessage(message, context)) 49 50 if not package.files_analyzed: 51 package_contains_relationships = filter_by_type_and_origin( 52 document.relationships, RelationshipType.CONTAINS, package.spdx_id 53 ) 54 package_contains_file_relationships = [ 55 relationship 56 for relationship in package_contains_relationships 57 if get_element_type_from_spdx_id(relationship.related_spdx_element_id, document) == File 58 ] 59 60 contained_in_package_relationships = filter_by_type_and_target( 61 document.relationships, RelationshipType.CONTAINED_BY, package.spdx_id 62 ) 63 file_contained_in_package_relationships = [ 64 relationship 65 for relationship in contained_in_package_relationships 66 if get_element_type_from_spdx_id(relationship.spdx_element_id, document) == File 67 ] 68 69 combined_relationships: List[Relationship] = ( 70 package_contains_file_relationships + file_contained_in_package_relationships 71 ) 72 73 if combined_relationships: 74 validation_messages.append( 75 ValidationMessage( 76 f"package must contain no elements if files_analyzed is False, but found {combined_relationships}", 77 context, 78 ) 79 ) 80 81 validation_messages.extend(validate_license_expression(package.license_concluded, document, package.spdx_id)) 82 83 license_info_from_files = package.license_info_from_files 84 if license_info_from_files: 85 if not package.files_analyzed: 86 validation_messages.append( 87 ValidationMessage( 88 f"license_info_from_files must be None if files_analyzed is False, but is: " 89 f"{license_info_from_files}", 90 context, 91 ) 92 ) 93 else: 94 validation_messages.extend( 95 validate_license_expressions(license_info_from_files, document, package.spdx_id) 96 ) 97 98 validation_messages.extend(validate_license_expression(package.license_declared, document, package.spdx_id)) 99 100 validation_messages.extend(validate_package(package, spdx_version, context)) 101 102 return validation_messages 103 104 105def validate_package( 106 package: Package, spdx_version: str, context: Optional[ValidationContext] = None 107) -> List[ValidationMessage]: 108 validation_messages: List[ValidationMessage] = [] 109 if not context: 110 context = ValidationContext( 111 spdx_id=package.spdx_id, element_type=SpdxElementType.PACKAGE, full_element=package 112 ) 113 114 download_location = package.download_location 115 if isinstance(download_location, str): 116 for message in validate_download_location(download_location): 117 validation_messages.append(ValidationMessage("package download_location " + message, context)) 118 119 homepage = package.homepage 120 if isinstance(homepage, str): 121 for message in validate_url(homepage): 122 validation_messages.append(ValidationMessage("homepage " + message, context)) 123 124 verification_code = package.verification_code 125 if verification_code: 126 if not package.files_analyzed: 127 validation_messages.append( 128 ValidationMessage( 129 f"verification_code must be None if files_analyzed is False, but is: {verification_code}", context 130 ) 131 ) 132 else: 133 validation_messages.extend(validate_verification_code(verification_code, package.spdx_id)) 134 135 validation_messages.extend(validate_checksums(package.checksums, package.spdx_id, spdx_version)) 136 137 validation_messages.extend( 138 validate_external_package_refs(package.external_references, package.spdx_id, spdx_version) 139 ) 140 141 if spdx_version == "SPDX-2.2": 142 if package.primary_package_purpose is not None: 143 validation_messages.append( 144 ValidationMessage("primary_package_purpose is not supported in SPDX-2.2", context) 145 ) 146 if package.built_date is not None: 147 validation_messages.append(ValidationMessage("built_date is not supported in SPDX-2.2", context)) 148 if package.release_date is not None: 149 validation_messages.append(ValidationMessage("release_date is not supported in SPDX-2.2", context)) 150 if package.valid_until_date is not None: 151 validation_messages.append(ValidationMessage("valid_until_date is not supported in SPDX-2.2", context)) 152 153 if package.license_concluded is None: 154 validation_messages.append(ValidationMessage("license_concluded is mandatory in SPDX-2.2", context)) 155 if package.license_declared is None: 156 validation_messages.append(ValidationMessage("license_declared is mandatory in SPDX-2.2", context)) 157 if package.copyright_text is None: 158 validation_messages.append(ValidationMessage("copyright_text is mandatory in SPDX-2.2", context)) 159 160 return validation_messages
def
validate_packages( packages: list[spdx_tools.spdx.model.package.Package], spdx_version: str, document: Optional[spdx_tools.spdx.model.document.Document] = None) -> list[spdx_tools.spdx.validation.validation_message.ValidationMessage]:
23def validate_packages( 24 packages: List[Package], spdx_version: str, document: Optional[Document] = None 25) -> List[ValidationMessage]: 26 validation_messages: List[ValidationMessage] = [] 27 if document: 28 for package in packages: 29 validation_messages.extend(validate_package_within_document(package, spdx_version, document)) 30 else: 31 for package in packages: 32 validation_messages.extend(validate_package(package, spdx_version)) 33 34 return validation_messages
def
validate_package_within_document( package: spdx_tools.spdx.model.package.Package, spdx_version: str, document: spdx_tools.spdx.model.document.Document) -> list[spdx_tools.spdx.validation.validation_message.ValidationMessage]:
37def validate_package_within_document( 38 package: Package, spdx_version: str, document: Document 39) -> List[ValidationMessage]: 40 validation_messages: List[ValidationMessage] = [] 41 context = ValidationContext( 42 spdx_id=package.spdx_id, 43 parent_id=document.creation_info.spdx_id, 44 element_type=SpdxElementType.PACKAGE, 45 full_element=package, 46 ) 47 48 for message in validate_spdx_id(package.spdx_id, document): 49 validation_messages.append(ValidationMessage(message, context)) 50 51 if not package.files_analyzed: 52 package_contains_relationships = filter_by_type_and_origin( 53 document.relationships, RelationshipType.CONTAINS, package.spdx_id 54 ) 55 package_contains_file_relationships = [ 56 relationship 57 for relationship in package_contains_relationships 58 if get_element_type_from_spdx_id(relationship.related_spdx_element_id, document) == File 59 ] 60 61 contained_in_package_relationships = filter_by_type_and_target( 62 document.relationships, RelationshipType.CONTAINED_BY, package.spdx_id 63 ) 64 file_contained_in_package_relationships = [ 65 relationship 66 for relationship in contained_in_package_relationships 67 if get_element_type_from_spdx_id(relationship.spdx_element_id, document) == File 68 ] 69 70 combined_relationships: List[Relationship] = ( 71 package_contains_file_relationships + file_contained_in_package_relationships 72 ) 73 74 if combined_relationships: 75 validation_messages.append( 76 ValidationMessage( 77 f"package must contain no elements if files_analyzed is False, but found {combined_relationships}", 78 context, 79 ) 80 ) 81 82 validation_messages.extend(validate_license_expression(package.license_concluded, document, package.spdx_id)) 83 84 license_info_from_files = package.license_info_from_files 85 if license_info_from_files: 86 if not package.files_analyzed: 87 validation_messages.append( 88 ValidationMessage( 89 f"license_info_from_files must be None if files_analyzed is False, but is: " 90 f"{license_info_from_files}", 91 context, 92 ) 93 ) 94 else: 95 validation_messages.extend( 96 validate_license_expressions(license_info_from_files, document, package.spdx_id) 97 ) 98 99 validation_messages.extend(validate_license_expression(package.license_declared, document, package.spdx_id)) 100 101 validation_messages.extend(validate_package(package, spdx_version, context)) 102 103 return validation_messages
def
validate_package( package: spdx_tools.spdx.model.package.Package, spdx_version: str, context: Optional[spdx_tools.spdx.validation.validation_message.ValidationContext] = None) -> list[spdx_tools.spdx.validation.validation_message.ValidationMessage]:
106def validate_package( 107 package: Package, spdx_version: str, context: Optional[ValidationContext] = None 108) -> List[ValidationMessage]: 109 validation_messages: List[ValidationMessage] = [] 110 if not context: 111 context = ValidationContext( 112 spdx_id=package.spdx_id, element_type=SpdxElementType.PACKAGE, full_element=package 113 ) 114 115 download_location = package.download_location 116 if isinstance(download_location, str): 117 for message in validate_download_location(download_location): 118 validation_messages.append(ValidationMessage("package download_location " + message, context)) 119 120 homepage = package.homepage 121 if isinstance(homepage, str): 122 for message in validate_url(homepage): 123 validation_messages.append(ValidationMessage("homepage " + message, context)) 124 125 verification_code = package.verification_code 126 if verification_code: 127 if not package.files_analyzed: 128 validation_messages.append( 129 ValidationMessage( 130 f"verification_code must be None if files_analyzed is False, but is: {verification_code}", context 131 ) 132 ) 133 else: 134 validation_messages.extend(validate_verification_code(verification_code, package.spdx_id)) 135 136 validation_messages.extend(validate_checksums(package.checksums, package.spdx_id, spdx_version)) 137 138 validation_messages.extend( 139 validate_external_package_refs(package.external_references, package.spdx_id, spdx_version) 140 ) 141 142 if spdx_version == "SPDX-2.2": 143 if package.primary_package_purpose is not None: 144 validation_messages.append( 145 ValidationMessage("primary_package_purpose is not supported in SPDX-2.2", context) 146 ) 147 if package.built_date is not None: 148 validation_messages.append(ValidationMessage("built_date is not supported in SPDX-2.2", context)) 149 if package.release_date is not None: 150 validation_messages.append(ValidationMessage("release_date is not supported in SPDX-2.2", context)) 151 if package.valid_until_date is not None: 152 validation_messages.append(ValidationMessage("valid_until_date is not supported in SPDX-2.2", context)) 153 154 if package.license_concluded is None: 155 validation_messages.append(ValidationMessage("license_concluded is mandatory in SPDX-2.2", context)) 156 if package.license_declared is None: 157 validation_messages.append(ValidationMessage("license_declared is mandatory in SPDX-2.2", context)) 158 if package.copyright_text is None: 159 validation_messages.append(ValidationMessage("copyright_text is mandatory in SPDX-2.2", context)) 160 161 return validation_messages