diff --git a/src/spdx/clitools/pyspdxtools.py b/src/spdx/clitools/pyspdxtools.py index 695cf99e8..ed32dbb77 100644 --- a/src/spdx/clitools/pyspdxtools.py +++ b/src/spdx/clitools/pyspdxtools.py @@ -27,7 +27,7 @@ @click.command() @click.option("--infile", "-i", help="The file containing the document to be validated or converted.") @click.option("--outfile", "-o", help="The file to write the converted document to (write a dash for output to stdout or omit for no conversion).") -@click.option("--version", help='The SPDX version to be used during parsing and validation (format "SPDX-2.3"). Will be read from the document if not provided.', default=None) +@click.option("--version", help='The SPDX version to be used during parsing and validation ("SPDX-2.2" or "SPDX-2.3"). Will be read from the document if not provided.', default=None) @click.option("--novalidation", is_flag=True, help="Don't validate the provided document.") def main(infile: str, outfile: str, version: str, novalidation: bool): """ @@ -45,6 +45,11 @@ def main(infile: str, outfile: str, version: str, novalidation: bool): if not version: version = document.creation_info.spdx_version + if not version in ["SPDX-2.2", "SPDX-2.3"]: + print(f"This tool only supports SPDX versions SPDX-2.2 and SPDX-2.3, but got: {version}", + file=sys.stderr) + sys.exit(1) + validation_messages: List[ValidationMessage] = validate_full_spdx_document(document, version) if validation_messages: print("The document is invalid. The following issues have been found:", file=sys.stderr) diff --git a/src/spdx/validation/checksum_validator.py b/src/spdx/validation/checksum_validator.py index b684ec772..1f4830336 100644 --- a/src/spdx/validation/checksum_validator.py +++ b/src/spdx/validation/checksum_validator.py @@ -37,20 +37,30 @@ } -def validate_checksums(checksums: List[Checksum], parent_id: str) -> List[ValidationMessage]: +def validate_checksums(checksums: List[Checksum], parent_id: str, spdx_version: str) -> List[ValidationMessage]: validation_messages = [] for checksum in checksums: - validation_messages.extend(validate_checksum(checksum, parent_id)) + validation_messages.extend(validate_checksum(checksum, parent_id, spdx_version)) return validation_messages -def validate_checksum(checksum: Checksum, parent_id: str) -> List[ValidationMessage]: +def validate_checksum(checksum: Checksum, parent_id: str, spdx_version: str) -> List[ValidationMessage]: validation_messages = [] algorithm = checksum.algorithm context = ValidationContext(parent_id=parent_id, element_type=SpdxElementType.CHECKSUM, full_element=checksum) + if spdx_version == "SPDX-2.2" and algorithm in [ChecksumAlgorithm.SHA3_512, + ChecksumAlgorithm.SHA3_384, + ChecksumAlgorithm.SHA3_256, + ChecksumAlgorithm.BLAKE3, + ChecksumAlgorithm.BLAKE2B_512, + ChecksumAlgorithm.BLAKE2B_384, + ChecksumAlgorithm.BLAKE2B_256, + ChecksumAlgorithm.ADLER32]: + return [ValidationMessage(f"{checksum.algorithm.name} is not supported in SPDX-2.2", context)] + if not re.match("^[0-9a-f]{" + algorithm_length[algorithm] + "}$", checksum.value): if algorithm == ChecksumAlgorithm.BLAKE3: length = "at least 256" diff --git a/src/spdx/validation/creation_info_validator.py b/src/spdx/validation/creation_info_validator.py index fc54740f6..3511e1d89 100644 --- a/src/spdx/validation/creation_info_validator.py +++ b/src/spdx/validation/creation_info_validator.py @@ -18,7 +18,7 @@ from spdx.validation.validation_message import ValidationMessage, ValidationContext, SpdxElementType -def validate_creation_info(creation_info: CreationInfo) -> List[ValidationMessage]: +def validate_creation_info(creation_info: CreationInfo, spdx_version: str) -> List[ValidationMessage]: validation_messages: List[ValidationMessage] = [] context = ValidationContext(spdx_id=creation_info.spdx_id, element_type=SpdxElementType.DOCUMENT) @@ -47,7 +47,7 @@ def validate_creation_info(creation_info: CreationInfo) -> List[ValidationMessag ) validation_messages.extend(validate_actors(creation_info.creators, creation_info.spdx_id)) - - validation_messages.extend(validate_external_document_refs(creation_info.external_document_refs, creation_info.spdx_id)) + validation_messages.extend( + validate_external_document_refs(creation_info.external_document_refs, creation_info.spdx_id, spdx_version)) return validation_messages diff --git a/src/spdx/validation/document_validator.py b/src/spdx/validation/document_validator.py index fe6422a21..264e8d400 100644 --- a/src/spdx/validation/document_validator.py +++ b/src/spdx/validation/document_validator.py @@ -8,7 +8,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -import re from typing import List from spdx.model.document import Document @@ -34,10 +33,10 @@ def validate_full_spdx_document(document: Document, spdx_version: str = None) -> if not spdx_version: spdx_version = document_version - if not re.match(r"^SPDX-\d+.\d+$", document_version): + if document_version not in ["SPDX-2.2", "SPDX-2.3"]: validation_messages.append( ValidationMessage( - f'the document\'s spdx_version must be of the form "SPDX-[major].[minor]" but is: {document_version}', + f'only SPDX versions "SPDX-2.2" and "SPDX-2.3" are supported, but the document\'s spdx_version is: {document_version}', context ) ) @@ -53,12 +52,12 @@ def validate_full_spdx_document(document: Document, spdx_version: str = None) -> "the validation process has been cancelled.", context)) return validation_messages - validation_messages.extend(validate_creation_info(document.creation_info)) - validation_messages.extend(validate_packages(document.packages, document)) - validation_messages.extend(validate_files(document.files, document)) - validation_messages.extend(validate_snippets(document.snippets, document)) + validation_messages.extend(validate_creation_info(document.creation_info, spdx_version)) + validation_messages.extend(validate_packages(document.packages, spdx_version, document)) + validation_messages.extend(validate_files(document.files, spdx_version, document)) + validation_messages.extend(validate_snippets(document.snippets, spdx_version, document)) validation_messages.extend(validate_annotations(document.annotations, document)) - validation_messages.extend(validate_relationships(document.relationships, document, spdx_version)) + validation_messages.extend(validate_relationships(document.relationships, spdx_version, document)) validation_messages.extend(validate_extracted_licensing_infos(document.extracted_licensing_info)) document_id = document.creation_info.spdx_id diff --git a/src/spdx/validation/external_document_ref_validator.py b/src/spdx/validation/external_document_ref_validator.py index 3d35434a7..99156566b 100644 --- a/src/spdx/validation/external_document_ref_validator.py +++ b/src/spdx/validation/external_document_ref_validator.py @@ -18,16 +18,17 @@ from spdx.validation.validation_message import ValidationMessage, ValidationContext, SpdxElementType -def validate_external_document_refs(external_document_refs: List[ExternalDocumentRef], parent_id: str) -> List[ - ValidationMessage]: +def validate_external_document_refs(external_document_refs: List[ExternalDocumentRef], parent_id: str, + spdx_version: str) -> List[ValidationMessage]: validation_messages = [] for external_document_ref in external_document_refs: - validation_messages.extend(validate_external_document_ref(external_document_ref, parent_id)) + validation_messages.extend(validate_external_document_ref(external_document_ref, parent_id, spdx_version)) return validation_messages -def validate_external_document_ref(external_document_ref: ExternalDocumentRef, parent_id: str) -> List[ValidationMessage]: +def validate_external_document_ref(external_document_ref: ExternalDocumentRef, parent_id: str, spdx_version: str) -> \ +List[ValidationMessage]: validation_messages = [] context = ValidationContext(parent_id=parent_id, element_type=SpdxElementType.EXTERNAL_DOCUMENT_REF, full_element=external_document_ref) @@ -47,6 +48,6 @@ def validate_external_document_ref(external_document_ref: ExternalDocumentRef, p ) ) - validation_messages.extend(validate_checksum(external_document_ref.checksum, parent_id)) + validation_messages.extend(validate_checksum(external_document_ref.checksum, parent_id, spdx_version)) return validation_messages diff --git a/src/spdx/validation/external_package_ref_validator.py b/src/spdx/validation/external_package_ref_validator.py index bff504d97..07a8f6bc4 100644 --- a/src/spdx/validation/external_package_ref_validator.py +++ b/src/spdx/validation/external_package_ref_validator.py @@ -14,7 +14,7 @@ import uritools from spdx.model.package import ExternalPackageRef, ExternalPackageRefCategory, CATEGORY_TO_EXTERNAL_PACKAGE_REF_TYPES -from spdx.validation.uri_validators import validate_url, validate_uri +from spdx.validation.uri_validators import validate_url from spdx.validation.validation_message import ValidationMessage, ValidationContext, SpdxElementType CPE22TYPE_REGEX = r'^c[pP][eE]:/[AHOaho]?(:[A-Za-z0-9._\-~%]*){0,6}$' @@ -40,16 +40,18 @@ } -def validate_external_package_refs(external_package_refs: List[ExternalPackageRef], parent_id: str) -> List[ - ValidationMessage]: +def validate_external_package_refs(external_package_refs: List[ExternalPackageRef], parent_id: str, + spdx_version: str) -> List[ValidationMessage]: validation_messages = [] for external_package_ref in external_package_refs: - validation_messages.extend(validate_external_package_ref(external_package_ref, parent_id)) + validation_messages.extend(validate_external_package_ref(external_package_ref, parent_id, spdx_version)) return validation_messages -def validate_external_package_ref(external_package_ref: ExternalPackageRef, parent_id: str) -> List[ValidationMessage]: +def validate_external_package_ref(external_package_ref: ExternalPackageRef, parent_id: str, spdx_version: str) -> List[ + ValidationMessage]: + validation_messages = [] context = ValidationContext(parent_id=parent_id, element_type=SpdxElementType.EXTERNAL_PACKAGE_REF, full_element=external_package_ref) @@ -59,31 +61,34 @@ def validate_external_package_ref(external_package_ref: ExternalPackageRef, pare if category == ExternalPackageRefCategory.OTHER: if " " in locator: - return [ValidationMessage( + validation_messages.append(ValidationMessage( f"externalPackageRef locator in category OTHER must contain no spaces, but is: {locator}", - context)] - return [] + context)) - if reference_type not in CATEGORY_TO_EXTERNAL_PACKAGE_REF_TYPES[category]: - return [ValidationMessage( + elif spdx_version == "SPDX-2.2" and reference_type in ["advisory", "fix", "url", "swid"]: + return [ValidationMessage(f'externalPackageRef type "{reference_type}" is not supported in SPDX-2.2', context)] + + elif reference_type not in CATEGORY_TO_EXTERNAL_PACKAGE_REF_TYPES[category]: + validation_messages.append(ValidationMessage( f"externalPackageRef type in category {category.name} must be one of {CATEGORY_TO_EXTERNAL_PACKAGE_REF_TYPES[category]}, but is: {reference_type}", - context)] + context)) - if reference_type in ["advisory", "fix", "url"]: + elif reference_type in ["advisory", "fix", "url"]: if validate_url(locator): - return [ValidationMessage( + validation_messages.append(ValidationMessage( f'externalPackageRef locator of type "{reference_type}" must be a valid URL, but is: {locator}', - context)] - return [] + context)) - if reference_type == "swid": + elif reference_type == "swid": if not uritools.isuri(locator) or not locator.startswith("swid"): - return [ValidationMessage( + validation_messages.append(ValidationMessage( f'externalPackageRef locator of type "swid" must be a valid URI with scheme swid, but is: {locator}', - context)] - return [] + context)) - return validate_against_regex(locator, reference_type, context) + else: + validation_messages.extend(validate_against_regex(locator, reference_type, context)) + + return validation_messages def validate_against_regex(string_to_validate: str, reference_type: str, context: ValidationContext) -> List[ diff --git a/src/spdx/validation/extracted_licensing_info_validator.py b/src/spdx/validation/extracted_licensing_info_validator.py index 92cd7c395..8b769e13d 100644 --- a/src/spdx/validation/extracted_licensing_info_validator.py +++ b/src/spdx/validation/extracted_licensing_info_validator.py @@ -17,7 +17,8 @@ from spdx.validation.validation_message import ValidationMessage, ValidationContext, SpdxElementType -def validate_extracted_licensing_infos(extracted_licensing_infos: Optional[List[ExtractedLicensingInfo]]) -> List[ValidationMessage]: +def validate_extracted_licensing_infos(extracted_licensing_infos: Optional[List[ExtractedLicensingInfo]]) -> List[ + ValidationMessage]: validation_messages = [] for extracted_licensing_info in extracted_licensing_infos: validation_messages.extend(validate_extracted_licensing_info(extracted_licensing_info)) diff --git a/src/spdx/validation/file_validator.py b/src/spdx/validation/file_validator.py index 16845e55d..a21f28fd7 100644 --- a/src/spdx/validation/file_validator.py +++ b/src/spdx/validation/file_validator.py @@ -20,19 +20,20 @@ from spdx.validation.validation_message import ValidationMessage, ValidationContext, SpdxElementType -def validate_files(files: List[File], document: Optional[Document] = None) -> List[ValidationMessage]: +def validate_files(files: List[File], spdx_version: str, document: Optional[Document] = None) -> List[ + ValidationMessage]: validation_messages = [] if document: for file in files: - validation_messages.extend(validate_file_within_document(file, document)) + validation_messages.extend(validate_file_within_document(file, spdx_version, document)) else: for file in files: - validation_messages.extend(validate_file(file)) + validation_messages.extend(validate_file(file, spdx_version)) return validation_messages -def validate_file_within_document(file: File, document: Document) -> List[ValidationMessage]: +def validate_file_within_document(file: File, spdx_version: str, document: Document) -> List[ValidationMessage]: validation_messages: List[ValidationMessage] = [] context = ValidationContext(spdx_id=file.spdx_id, parent_id=document.creation_info.spdx_id, element_type=SpdxElementType.FILE, full_element=file) @@ -40,12 +41,13 @@ def validate_file_within_document(file: File, document: Document) -> List[Valida for message in validate_spdx_id(file.spdx_id, document): validation_messages.append(ValidationMessage(message, context)) - validation_messages.extend(validate_file(file, context)) + validation_messages.extend(validate_file(file, spdx_version, context)) return validation_messages -def validate_file(file: File, context: Optional[ValidationContext] = None) -> List[ValidationMessage]: +def validate_file(file: File, spdx_version: str, context: Optional[ValidationContext] = None) -> List[ + ValidationMessage]: validation_messages = [] if not context: context = ValidationContext(spdx_id=file.spdx_id, element_type=SpdxElementType.FILE, full_element=file) @@ -63,10 +65,21 @@ def validate_file(file: File, context: Optional[ValidationContext] = None) -> Li context) ) - validation_messages.extend(validate_checksums(file.checksums, file.spdx_id)) + validation_messages.extend(validate_checksums(file.checksums, file.spdx_id, spdx_version)) validation_messages.extend(validate_license_expression(file.license_concluded)) validation_messages.extend(validate_license_expressions(file.license_info_in_file)) + if spdx_version == "SPDX-2.2": + if file.license_concluded is None: + validation_messages.append( + ValidationMessage(f"license_concluded is mandatory in SPDX-2.2", context)) + if not file.license_info_in_file: + validation_messages.append( + ValidationMessage(f"license_info_in_file is mandatory in SPDX-2.2", context)) + if file.copyright_text is None: + validation_messages.append( + ValidationMessage(f"copyright_text is mandatory in SPDX-2.2", context)) + return validation_messages diff --git a/src/spdx/validation/package_validator.py b/src/spdx/validation/package_validator.py index f73f42eff..888911002 100644 --- a/src/spdx/validation/package_validator.py +++ b/src/spdx/validation/package_validator.py @@ -24,19 +24,21 @@ from spdx.validation.validation_message import ValidationMessage, ValidationContext, SpdxElementType -def validate_packages(packages: List[Package], document: Optional[Document] = None) -> List[ValidationMessage]: +def validate_packages(packages: List[Package], spdx_version: str, document: Optional[Document] = None) -> List[ + ValidationMessage]: validation_messages: List[ValidationMessage] = [] if document: for package in packages: - validation_messages.extend(validate_package_within_document(package, document)) + validation_messages.extend(validate_package_within_document(package, spdx_version, document)) else: for package in packages: - validation_messages.extend(validate_package(package)) + validation_messages.extend(validate_package(package, spdx_version)) return validation_messages -def validate_package_within_document(package: Package, document: Document) -> List[ValidationMessage]: +def validate_package_within_document(package: Package, spdx_version: str, document: Document) -> List[ + ValidationMessage]: validation_messages: List[ValidationMessage] = [] context = ValidationContext(spdx_id=package.spdx_id, parent_id=document.creation_info.spdx_id, element_type=SpdxElementType.PACKAGE, full_element=package) @@ -59,12 +61,13 @@ def validate_package_within_document(package: Package, document: Document) -> Li context) ) - validation_messages.extend(validate_package(package, context)) + validation_messages.extend(validate_package(package, spdx_version, context)) return validation_messages -def validate_package(package: Package, context: Optional[ValidationContext] = None) -> List[ValidationMessage]: +def validate_package(package: Package, spdx_version: str, context: Optional[ValidationContext] = None) -> List[ + ValidationMessage]: validation_messages: List[ValidationMessage] = [] if not context: context = ValidationContext(spdx_id=package.spdx_id, element_type=SpdxElementType.PACKAGE, full_element=package) @@ -89,7 +92,7 @@ def validate_package(package: Package, context: Optional[ValidationContext] = No else: validation_messages.extend(validate_verification_code(verification_code, package.spdx_id)) - validation_messages.extend(validate_checksums(package.checksums, package.spdx_id)) + validation_messages.extend(validate_checksums(package.checksums, package.spdx_id, spdx_version)) validation_messages.extend(validate_license_expression(package.license_concluded)) @@ -106,6 +109,31 @@ def validate_package(package: Package, context: Optional[ValidationContext] = No validation_messages.extend(validate_license_expression(package.license_declared)) - validation_messages.extend(validate_external_package_refs(package.external_references, package.spdx_id)) + validation_messages.extend( + validate_external_package_refs(package.external_references, package.spdx_id, spdx_version)) + + if spdx_version == "SPDX-2.2": + if package.primary_package_purpose is not None: + validation_messages.append( + ValidationMessage(f"primary_package_purpose is not supported in SPDX-2.2", context)) + if package.built_date is not None: + validation_messages.append( + ValidationMessage(f"built_date is not supported in SPDX-2.2", context)) + if package.release_date is not None: + validation_messages.append( + ValidationMessage(f"release_date is not supported in SPDX-2.2", context)) + if package.valid_until_date is not None: + validation_messages.append( + ValidationMessage(f"valid_until_date is not supported in SPDX-2.2", context)) + + if package.license_concluded is None: + validation_messages.append( + ValidationMessage(f"license_concluded is mandatory in SPDX-2.2", context)) + if package.license_declared is None: + validation_messages.append( + ValidationMessage(f"license_declared is mandatory in SPDX-2.2", context)) + if package.copyright_text is None: + validation_messages.append( + ValidationMessage(f"copyright_text is mandatory in SPDX-2.2", context)) return validation_messages diff --git a/src/spdx/validation/relationship_validator.py b/src/spdx/validation/relationship_validator.py index f919ebaae..4fa310970 100644 --- a/src/spdx/validation/relationship_validator.py +++ b/src/spdx/validation/relationship_validator.py @@ -19,15 +19,16 @@ from spdx.validation.validation_message import ValidationMessage, ValidationContext, SpdxElementType -def validate_relationships(relationships: List[Relationship], document: Document, spdx_version: str) -> List[ValidationMessage]: +def validate_relationships(relationships: List[Relationship], spdx_version: str, document: Document) -> List[ + ValidationMessage]: validation_messages = [] for relationship in relationships: - validation_messages.extend(validate_relationship(relationship, document, spdx_version)) + validation_messages.extend(validate_relationship(relationship, spdx_version, document)) return validation_messages -def validate_relationship(relationship: Relationship, document: Document, spdx_version: str) -> List[ValidationMessage]: +def validate_relationship(relationship: Relationship, spdx_version: str, document: Document) -> List[ValidationMessage]: validation_messages = [] context = ValidationContext(element_type=SpdxElementType.RELATIONSHIP, full_element=relationship) @@ -43,9 +44,9 @@ def validate_relationship(relationship: Relationship, document: Document, spdx_v for message in messages: validation_messages.append(ValidationMessage(message, context)) - if spdx_version != "SPDX-2.3": + if spdx_version == "SPDX-2.2": if relationship_type == RelationshipType.SPECIFICATION_FOR or relationship_type == RelationshipType.REQUIREMENT_DESCRIPTION_FOR: validation_messages.append( - ValidationMessage(f"{relationship_type} is not supported for SPDX versions below SPDX-2.3", context)) + ValidationMessage(f"{relationship_type} is not supported in SPDX-2.2", context)) return validation_messages diff --git a/src/spdx/validation/snippet_validator.py b/src/spdx/validation/snippet_validator.py index 4d350f353..21d2e0d44 100644 --- a/src/spdx/validation/snippet_validator.py +++ b/src/spdx/validation/snippet_validator.py @@ -19,19 +19,21 @@ from spdx.validation.validation_message import ValidationMessage, ValidationContext, SpdxElementType -def validate_snippets(snippets: List[Snippet], document: Optional[Document] = None) -> List[ValidationMessage]: +def validate_snippets(snippets: List[Snippet], spdx_version: str, document: Optional[Document] = None) -> List[ + ValidationMessage]: validation_messages = [] if document: for snippet in snippets: - validation_messages.extend(validate_snippet_within_document(snippet, document)) + validation_messages.extend(validate_snippet_within_document(snippet, spdx_version, document)) else: for snippet in snippets: - validation_messages.extend(validate_snippet(snippet)) + validation_messages.extend(validate_snippet(snippet, spdx_version)) return validation_messages -def validate_snippet_within_document(snippet: Snippet, document: Document) -> List[ValidationMessage]: +def validate_snippet_within_document(snippet: Snippet, spdx_version: str, document: Document) -> List[ + ValidationMessage]: validation_messages: List[ValidationMessage] = [] context = ValidationContext(spdx_id=snippet.spdx_id, parent_id=document.creation_info.spdx_id, element_type=SpdxElementType.SNIPPET, full_element=snippet) @@ -44,12 +46,13 @@ def validate_snippet_within_document(snippet: Snippet, document: Document) -> Li for message in messages: validation_messages.append(ValidationMessage(message, context)) - validation_messages.extend(validate_snippet(snippet, context)) + validation_messages.extend(validate_snippet(snippet, spdx_version, context)) return validation_messages -def validate_snippet(snippet: Snippet, context: Optional[ValidationContext] = None) -> List[ValidationMessage]: +def validate_snippet(snippet: Snippet, spdx_version: str, context: Optional[ValidationContext] = None) -> List[ + ValidationMessage]: validation_messages = [] if not context: context = ValidationContext(spdx_id=snippet.spdx_id, element_type=SpdxElementType.SNIPPET, full_element=snippet) @@ -87,4 +90,12 @@ def validate_snippet(snippet: Snippet, context: Optional[ValidationContext] = No validation_messages.extend(validate_license_expressions(snippet.license_info_in_snippet)) + if spdx_version == "SPDX-2.2": + if snippet.license_concluded is None: + validation_messages.append( + ValidationMessage(f"license_concluded is mandatory in SPDX-2.2", context)) + if snippet.copyright_text is None: + validation_messages.append( + ValidationMessage(f"copyright_text is mandatory in SPDX-2.2", context)) + return validation_messages diff --git a/tests/spdx/validation/test_checksum_validator.py b/tests/spdx/validation/test_checksum_validator.py index 7fd5f56d2..995806a28 100644 --- a/tests/spdx/validation/test_checksum_validator.py +++ b/tests/spdx/validation/test_checksum_validator.py @@ -51,7 +51,7 @@ "af1eec2a1b18886c3f3cc244349d91d8d4c41ce30a517d6ce9d79c8c17bb4b660d7f61beb7018b3924c6b8f96549fa39"), Checksum(ChecksumAlgorithm.ADLER32, "02ec0130")]) def test_valid_checksum(checksum): - validation_messages: List[ValidationMessage] = validate_checksum(checksum, "parent_id") + validation_messages: List[ValidationMessage] = validate_checksum(checksum, "parent_id", "SPDX-2.3") assert validation_messages == [] @@ -97,10 +97,37 @@ def test_valid_checksum(checksum): ]) def test_invalid_checksum(checksum, expected_message): parent_id = "parent_id" - validation_messages: List[ValidationMessage] = validate_checksum(checksum, parent_id) + validation_messages: List[ValidationMessage] = validate_checksum(checksum, parent_id, "SPDX-2.3") expected = ValidationMessage(expected_message, ValidationContext(parent_id=parent_id, element_type=SpdxElementType.CHECKSUM, full_element=checksum)) assert validation_messages == [expected] + + +@pytest.mark.parametrize("checksum", + [Checksum(ChecksumAlgorithm.SHA3_256, + "1e772489c042f49aeaae32b00fc5ef170a25afa741cffaafadde597d4d1727ce"), + Checksum(ChecksumAlgorithm.SHA3_384, + "dd9e30747551865b483bd76bd967384dce0e5670d1b1c3f701cffac7f49b1c46791253493835136b3aa5f679e364c166"), + Checksum(ChecksumAlgorithm.SHA3_512, + "906bca5580be8c95ae44f775363fb69968ad568898dfb03e0ff96cd9445a0b75f817b68e5c1e80ad624031f851cfddd3a101e1d111310266a5d46e2bc1ffbb36"), + Checksum(ChecksumAlgorithm.BLAKE2B_256, + "a0eb3ddfa5807780a562b9c313b2537f1e8dc621e9a524f8c1ffcf07a79e35c7"), + Checksum(ChecksumAlgorithm.BLAKE2B_384, + "902511afc8939c0193d87857f45a19eddfd7e0413b0f8701a3baaf1b025f882b45a8fbf623fa0ad79b64850ac7a4d0b2"), + Checksum(ChecksumAlgorithm.BLAKE2B_512, + "72c23b0160e1af3cb159f0cc96210c5e9aecc5a65d4618566776fa6117bf84929dcef56c7f8b087691c23000c945470842d90b5e8c4af74dce531ca8ebd8824c"), + Checksum(ChecksumAlgorithm.BLAKE3, + "a872cac2efd29ed2ad8b5faa79b63f983341bea41183582b8863d952f6ac3e1cdfe0189967a13006857d3b9985174bf67239874dcec4cbbc9839496179feafeda872cac2efd29ed2ad8b5faa79b63f983341bea41183582b8863d952f6ac3e1cdfe0189967a13006857d3b9985174bf67239874dcec4cbbc9839496179feafed"), + Checksum(ChecksumAlgorithm.ADLER32, "02ec0130") + ]) +def test_v2_3only_checksums(checksum): + parent_id = "parent_id" + validation_messages: List[ValidationMessage] = validate_checksum(checksum, parent_id, "SPDX-2.2") + + context = ValidationContext(parent_id=parent_id, element_type=SpdxElementType.CHECKSUM, full_element=checksum) + expected = ValidationMessage(f"{checksum.algorithm.name} is not supported in SPDX-2.2", context) + + assert validation_messages == [expected] diff --git a/tests/spdx/validation/test_creation_info_validator.py b/tests/spdx/validation/test_creation_info_validator.py index 0fb4fc746..4e62e6fbc 100644 --- a/tests/spdx/validation/test_creation_info_validator.py +++ b/tests/spdx/validation/test_creation_info_validator.py @@ -20,7 +20,7 @@ def test_valid_creation_info(): creation_info = creation_info_fixture() - validation_messages: List[ValidationMessage] = validate_creation_info(creation_info) + validation_messages: List[ValidationMessage] = validate_creation_info(creation_info, "SPDX-2.3") assert validation_messages == [] @@ -35,7 +35,7 @@ def test_valid_creation_info(): "document_namespace must be a valid URI specified in RFC-3986 and must contain no fragment (#), but is: some_namespace"), ]) def test_invalid_creation_info(creation_info_input, expected_message, spdx_id): - validation_messages: List[ValidationMessage] = validate_creation_info(creation_info_input) + validation_messages: List[ValidationMessage] = validate_creation_info(creation_info_input, "SPDX-2.3") expected = ValidationMessage(expected_message, ValidationContext(spdx_id, None, SpdxElementType.DOCUMENT)) diff --git a/tests/spdx/validation/test_document_validator.py b/tests/spdx/validation/test_document_validator.py index 0ee0aff9d..f9a66d1b5 100644 --- a/tests/spdx/validation/test_document_validator.py +++ b/tests/spdx/validation/test_document_validator.py @@ -35,11 +35,13 @@ def test_valid_document(): (creation_info_fixture(spdx_version="SPDX-2.3"), "SPDX2.3", "provided SPDX version SPDX2.3 does not match the document's SPDX version SPDX-2.3"), (creation_info_fixture(spdx_version="SPDX2.3"), "SPDX-2.3", - 'the document\'s spdx_version must be of the form "SPDX-[major].[minor]" but is: SPDX2.3'), + 'only SPDX versions "SPDX-2.2" and "SPDX-2.3" are supported, but the document\'s spdx_version is: SPDX2.3'), (creation_info_fixture(spdx_version="SPDX2.3"), None, - 'the document\'s spdx_version must be of the form "SPDX-[major].[minor]" but is: SPDX2.3'), + 'only SPDX versions "SPDX-2.2" and "SPDX-2.3" are supported, but the document\'s spdx_version is: SPDX2.3'), (creation_info_fixture(spdx_version="SPDX2.3"), "SPDX2.3", - 'the document\'s spdx_version must be of the form "SPDX-[major].[minor]" but is: SPDX2.3'), + 'only SPDX versions "SPDX-2.2" and "SPDX-2.3" are supported, but the document\'s spdx_version is: SPDX2.3'), + (creation_info_fixture(spdx_version="SPDX-2.1"), "SPDX-2.1", + 'only SPDX versions "SPDX-2.2" and "SPDX-2.3" are supported, but the document\'s spdx_version is: SPDX-2.1'), ]) def test_spdx_version_handling(creation_info: CreationInfo, version_input: str, expected_message: Optional[str]): document: Document = document_fixture(creation_info=creation_info) @@ -68,7 +70,8 @@ def test_document_describes_at_least_one_element(relationships): def test_document_does_not_describe_an_element(): - document = document_fixture(relationships=[Relationship("SPDXRef-Package", RelationshipType.DESCRIBES, "SPDXRef-File")]) + document = document_fixture( + relationships=[Relationship("SPDXRef-Package", RelationshipType.DESCRIBES, "SPDXRef-File")]) validation_messages: List[ValidationMessage] = validate_full_spdx_document(document) assert validation_messages == [ValidationMessage( @@ -79,7 +82,8 @@ def test_document_does_not_describe_an_element(): def test_duplicated_spdx_ids(): document = document_fixture( - files=[file_fixture(spdx_id="SPDXRef-File"), file_fixture(spdx_id="SPDXRef-2"), file_fixture(spdx_id="SPDXRef-3")], + files=[file_fixture(spdx_id="SPDXRef-File"), file_fixture(spdx_id="SPDXRef-2"), + file_fixture(spdx_id="SPDXRef-3")], packages=[package_fixture(spdx_id="SPDXRef-2"), package_fixture(spdx_id="SPDXRef-DOCUMENT")], snippets=[snippet_fixture(spdx_id="SPDXRef-2"), snippet_fixture(spdx_id="SPDXRef-3")]) diff --git a/tests/spdx/validation/test_external_document_ref_validator.py b/tests/spdx/validation/test_external_document_ref_validator.py index 5010f69cb..a81bc7b9d 100644 --- a/tests/spdx/validation/test_external_document_ref_validator.py +++ b/tests/spdx/validation/test_external_document_ref_validator.py @@ -18,6 +18,7 @@ def test_valid_external_document_ref(): external_document_ref = external_document_ref_fixture() - validation_messages: List[ValidationMessage] = validate_external_document_ref(external_document_ref, "parent_id") + validation_messages: List[ValidationMessage] = validate_external_document_ref(external_document_ref, "parent_id", + "SPDX-2.3") assert validation_messages == [] diff --git a/tests/spdx/validation/test_external_package_ref_validator.py b/tests/spdx/validation/test_external_package_ref_validator.py index f0085c868..e9e50f7f5 100644 --- a/tests/spdx/validation/test_external_package_ref_validator.py +++ b/tests/spdx/validation/test_external_package_ref_validator.py @@ -76,26 +76,29 @@ ]) def test_valid_external_package_ref(category, reference_type, locator): external_package_ref = ExternalPackageRef(category, reference_type, locator, "externalPackageRef comment") - validation_messages: List[ValidationMessage] = validate_external_package_ref(external_package_ref, "parent_id") + validation_messages: List[ValidationMessage] = validate_external_package_ref(external_package_ref, "parent_id", + "SPDX-2.3") assert validation_messages == [] @pytest.mark.parametrize("category, reference_type, locator, expected_message", [( - ExternalPackageRefCategory.SECURITY, "cpe22Typo", "cpe:/o:canonical:ubuntu_linux:10.04:-:lts", - "externalPackageRef type in category SECURITY must be one of ['cpe22Type', 'cpe23Type', 'advisory', 'fix', 'url', 'swid'], but is: cpe22Typo"), - (ExternalPackageRefCategory.PACKAGE_MANAGER, "nugat", - "cpe:/o:canonical:ubuntu_linux:10.04:-:lts", - "externalPackageRef type in category PACKAGE_MANAGER must be one of ['maven-central', 'npm', 'nuget', 'bower', 'purl'], but is: nugat"), - (ExternalPackageRefCategory.PERSISTENT_ID, "git-oid", - "cpe:/o:canonical:ubuntu_linux:10.04:-:lts", - "externalPackageRef type in category PERSISTENT_ID must be one of ['swh', 'gitoid'], but is: git-oid") - ]) + ExternalPackageRefCategory.SECURITY, "cpe22Typo", + "cpe:/o:canonical:ubuntu_linux:10.04:-:lts", + "externalPackageRef type in category SECURITY must be one of ['cpe22Type', 'cpe23Type', 'advisory', 'fix', 'url', 'swid'], but is: cpe22Typo"), + (ExternalPackageRefCategory.PACKAGE_MANAGER, "nugat", + "cpe:/o:canonical:ubuntu_linux:10.04:-:lts", + "externalPackageRef type in category PACKAGE_MANAGER must be one of ['maven-central', 'npm', 'nuget', 'bower', 'purl'], but is: nugat"), + (ExternalPackageRefCategory.PERSISTENT_ID, "git-oid", + "cpe:/o:canonical:ubuntu_linux:10.04:-:lts", + "externalPackageRef type in category PERSISTENT_ID must be one of ['swh', 'gitoid'], but is: git-oid") + ]) def test_invalid_external_package_ref_types(category, reference_type, locator, expected_message): external_package_ref = ExternalPackageRef(category, reference_type, locator, "externalPackageRef comment") parent_id = "SPDXRef-Package" - validation_messages: List[ValidationMessage] = validate_external_package_ref(external_package_ref, parent_id) + validation_messages: List[ValidationMessage] = validate_external_package_ref(external_package_ref, parent_id, + "SPDX-2.3") expected = ValidationMessage(expected_message, ValidationContext(parent_id=parent_id, @@ -145,7 +148,8 @@ def test_invalid_external_package_ref_types(category, reference_type, locator, e def test_invalid_external_package_ref_locators(category, reference_type, locator, expected_message): external_package_ref = ExternalPackageRef(category, reference_type, locator, "externalPackageRef comment") parent_id = "SPDXRef-Package" - validation_messages: List[ValidationMessage] = validate_external_package_ref(external_package_ref, parent_id) + validation_messages: List[ValidationMessage] = validate_external_package_ref(external_package_ref, parent_id, + "SPDX-2.3") expected = ValidationMessage(expected_message, ValidationContext(parent_id=parent_id, @@ -153,3 +157,26 @@ def test_invalid_external_package_ref_locators(category, reference_type, locator full_element=external_package_ref)) assert validation_messages == [expected] + + +@pytest.mark.parametrize("category, reference_type, locator", + [(ExternalPackageRefCategory.SECURITY, "advisory", + "https://nvd.nist.gov/vuln/detail/CVE-2020-28498"), + (ExternalPackageRefCategory.SECURITY, "fix", + "https://github.com/indutny/elliptic/commit/441b7428"), + (ExternalPackageRefCategory.SECURITY, "url", + "https://github.com/christianlundkvist/blog/blob/master/2020_05_26_secp256k1_twist_attacks/secp256k1_twist_attacks.md"), + (ExternalPackageRefCategory.SECURITY, "swid", "swid:2df9de35-0aff-4a86-ace6-f7dddd1ade4c") + ]) +def test_v2_3only_external_package_ref_types(category, reference_type, locator): + external_package_ref = ExternalPackageRef(category, reference_type, locator, "externalPackageRef comment") + parent_id = "SPDXRef-Package" + validation_messages: List[ValidationMessage] = validate_external_package_ref(external_package_ref, parent_id, + "SPDX-2.2") + + expected = ValidationMessage(f'externalPackageRef type "{reference_type}" is not supported in SPDX-2.2', + ValidationContext(parent_id=parent_id, + element_type=SpdxElementType.EXTERNAL_PACKAGE_REF, + full_element=external_package_ref)) + + assert validation_messages == [expected] diff --git a/tests/spdx/validation/test_file_validator.py b/tests/spdx/validation/test_file_validator.py index d06a24d63..b1fb6b41d 100644 --- a/tests/spdx/validation/test_file_validator.py +++ b/tests/spdx/validation/test_file_validator.py @@ -10,18 +10,19 @@ # limitations under the License. from typing import List +from unittest import TestCase import pytest from spdx.model.checksum import Checksum, ChecksumAlgorithm -from spdx.validation.file_validator import validate_file_within_document +from spdx.validation.file_validator import validate_file_within_document, validate_file from spdx.validation.validation_message import ValidationMessage, ValidationContext, SpdxElementType from tests.spdx.fixtures import file_fixture, document_fixture def test_valid_file(): file = file_fixture() - validation_messages: List[ValidationMessage] = validate_file_within_document(file, document_fixture()) + validation_messages: List[ValidationMessage] = validate_file_within_document(file, "SPDX-2.3", document_fixture()) assert validation_messages == [] @@ -29,13 +30,14 @@ def test_valid_file(): @pytest.mark.parametrize("file_input, spdx_id, expected_message", [(file_fixture(name="/invalid/file/name"), file_fixture().spdx_id, f'file name must not be an absolute path starting with "/", but is: /invalid/file/name'), - ( + ( file_fixture(checksums=[Checksum(ChecksumAlgorithm.MD2, "d4c41ce30a517d6ce9d79c8c17bb4b66")]), file_fixture().spdx_id, f'checksums must contain a SHA1 algorithm checksum, but only contains: []') ]) def test_invalid_file(file_input, spdx_id, expected_message): - validation_messages: List[ValidationMessage] = validate_file_within_document(file_input, document_fixture()) + validation_messages: List[ValidationMessage] = validate_file_within_document(file_input, "SPDX-2.3", + document_fixture()) expected = ValidationMessage(expected_message, ValidationContext(spdx_id=spdx_id, @@ -44,3 +46,17 @@ def test_invalid_file(file_input, spdx_id, expected_message): full_element=file_input)) assert validation_messages == [expected] + + +def test_v2_2mandatory_fields(): + file = file_fixture(license_concluded=None, license_info_in_file=[], copyright_text=None) + + assert validate_file(file, "SPDX-2.3") == [] + + validation_messages: List[ValidationMessage] = validate_file(file, "SPDX-2.2") + + context = ValidationContext(spdx_id=file.spdx_id, element_type=SpdxElementType.FILE, full_element=file) + mandatory_fields = ["license_concluded", "license_info_in_file", "copyright_text"] + expected = [ValidationMessage(f"{field} is mandatory in SPDX-2.2", context) for field in mandatory_fields] + + TestCase().assertCountEqual(validation_messages, expected) diff --git a/tests/spdx/validation/test_package_validator.py b/tests/spdx/validation/test_package_validator.py index fa7923982..72391fc8e 100644 --- a/tests/spdx/validation/test_package_validator.py +++ b/tests/spdx/validation/test_package_validator.py @@ -10,6 +10,7 @@ # limitations under the License. from typing import List +from unittest import TestCase import pytest from license_expression import Licensing @@ -17,14 +18,15 @@ from spdx.model.relationship import Relationship, RelationshipType from spdx.model.spdx_no_assertion import SpdxNoAssertion from spdx.model.spdx_none import SpdxNone -from spdx.validation.package_validator import validate_package_within_document +from spdx.validation.package_validator import validate_package_within_document, validate_package from spdx.validation.validation_message import ValidationMessage, ValidationContext, SpdxElementType from tests.spdx.fixtures import package_fixture, package_verification_code_fixture, document_fixture, file_fixture def test_valid_package(): package = package_fixture() - validation_messages: List[ValidationMessage] = validate_package_within_document(package, document_fixture()) + validation_messages: List[ValidationMessage] = validate_package_within_document(package, "SPDX-2.3", + document_fixture()) assert validation_messages == [] @@ -46,7 +48,7 @@ def test_valid_package(): "is_exception=False)]") ]) def test_invalid_package(package_input, expected_message): - validation_messages: List[ValidationMessage] = validate_package_within_document(package_input, + validation_messages: List[ValidationMessage] = validate_package_within_document(package_input, "SPDX-2.3", document_fixture(relationships=[])) expected = ValidationMessage(expected_message, @@ -59,9 +61,11 @@ def test_invalid_package(package_input, expected_message): @pytest.mark.parametrize("relationships", [[Relationship("SPDXRef-Package", RelationshipType.CONTAINS, "SPDXRef-File1")], - [Relationship("SPDXRef-Package", RelationshipType.CONTAINS, "DocumentRef-external:SPDXRef-File")], + [Relationship("SPDXRef-Package", RelationshipType.CONTAINS, + "DocumentRef-external:SPDXRef-File")], [Relationship("SPDXRef-File2", RelationshipType.CONTAINED_BY, "SPDXRef-Package")], - [Relationship("DocumentRef-external:SPDXRef-File", RelationshipType.CONTAINED_BY, "SPDXRef-Package")], + [Relationship("DocumentRef-external:SPDXRef-File", RelationshipType.CONTAINED_BY, + "SPDXRef-Package")], [Relationship("SPDXRef-Package", RelationshipType.CONTAINS, "SPDXRef-File2"), Relationship("SPDXRef-File1", RelationshipType.CONTAINED_BY, "SPDXRef-Package")]]) def test_invalid_package_with_contains(relationships): @@ -72,8 +76,34 @@ def test_invalid_package_with_contains(relationships): element_type=SpdxElementType.PACKAGE, full_element=package) - validation_messages: List[ValidationMessage] = validate_package_within_document(package, document) + validation_messages: List[ValidationMessage] = validate_package_within_document(package, "SPDX-2.3", document) assert validation_messages == [ ValidationMessage(f"package must contain no elements if files_analyzed is False, but found {relationships}", context)] + + +def test_v2_3only_fields(): + package = package_fixture() + validation_messages: List[ValidationMessage] = validate_package(package, "SPDX-2.2") + + context = ValidationContext(spdx_id=package.spdx_id, element_type=SpdxElementType.PACKAGE, full_element=package) + unsupported_fields = ["primary_package_purpose", "built_date", "release_date", "valid_until_date"] + expected = [ValidationMessage(f"{field} is not supported in SPDX-2.2", context) for field in unsupported_fields] + + TestCase().assertCountEqual(validation_messages, expected) + + +def test_v2_2mandatory_fields(): + package = package_fixture(license_concluded=None, license_declared=None, copyright_text=None, + primary_package_purpose=None, built_date=None, release_date=None, valid_until_date=None) + + assert validate_package(package, "SPDX-2.3") == [] + + validation_messages: List[ValidationMessage] = validate_package(package, "SPDX-2.2") + + context = ValidationContext(spdx_id=package.spdx_id, element_type=SpdxElementType.PACKAGE, full_element=package) + mandatory_fields = ["license_concluded", "license_declared", "copyright_text"] + expected = [ValidationMessage(f"{field} is mandatory in SPDX-2.2", context) for field in mandatory_fields] + + TestCase().assertCountEqual(validation_messages, expected) diff --git a/tests/spdx/validation/test_package_verification_code_validator.py b/tests/spdx/validation/test_package_verification_code_validator.py index 5ed3ae4ce..d94d56be3 100644 --- a/tests/spdx/validation/test_package_verification_code_validator.py +++ b/tests/spdx/validation/test_package_verification_code_validator.py @@ -28,7 +28,8 @@ def test_valid_package_verification_code(): "value of verification_code must consist of 40 lowercase hexadecimal digits, but is: 71c4025dd9897b364f3ebbb42c484ff43d00791cab (length: 42 digits)"), (PackageVerificationCode("CE9F343C4BA371746FD7EAD9B59031AE34D8AFC4", []), "value of verification_code must consist of 40 lowercase hexadecimal digits, but is: CE9F343C4BA371746FD7EAD9B59031AE34D8AFC4 (length: 40 digits)"), - (PackageVerificationCode("71c4025dd9897b364f3ebbb42c484ff43d00791c", ["/invalid/excluded/file"]), + (PackageVerificationCode("71c4025dd9897b364f3ebbb42c484ff43d00791c", + ["/invalid/excluded/file"]), 'file name must not be an absolute path starting with "/", but is: /invalid/excluded/file') ]) def test_invalid_package_verification_code(code, expected_message): diff --git a/tests/spdx/validation/test_relationship_validator.py b/tests/spdx/validation/test_relationship_validator.py index 89ea0883d..32e4c114b 100644 --- a/tests/spdx/validation/test_relationship_validator.py +++ b/tests/spdx/validation/test_relationship_validator.py @@ -26,7 +26,7 @@ ["SPDXRef-Package", SpdxNoAssertion(), SpdxNone()]) def test_valid_relationship(related_spdx_element): relationship = Relationship("SPDXRef-DOCUMENT", RelationshipType.DESCRIBES, related_spdx_element, comment="comment") - validation_messages: List[ValidationMessage] = validate_relationship(relationship, document_fixture(), "2.3") + validation_messages: List[ValidationMessage] = validate_relationship(relationship, "SPDX-2.3", document_fixture()) assert validation_messages == [] @@ -40,7 +40,7 @@ def test_valid_relationship(related_spdx_element): def test_unknown_spdx_id(spdx_element_id, related_spdx_element_id, expected_message): relationship: Relationship = relationship_fixture(spdx_element_id=spdx_element_id, related_spdx_element_id=related_spdx_element_id) - validation_messages: List[ValidationMessage] = validate_relationship(relationship, document_fixture(), "SPDX-2.3") + validation_messages: List[ValidationMessage] = validate_relationship(relationship, "SPDX-2.3", document_fixture()) expected = ValidationMessage(expected_message, ValidationContext(element_type=SpdxElementType.RELATIONSHIP, @@ -51,14 +51,14 @@ def test_unknown_spdx_id(spdx_element_id, related_spdx_element_id, expected_mess @pytest.mark.parametrize("relationship, expected_message", [(Relationship("SPDXRef-DOCUMENT", RelationshipType.SPECIFICATION_FOR, "SPDXRef-Package"), - "RelationshipType.SPECIFICATION_FOR is not supported for SPDX versions below SPDX-2.3"), + "RelationshipType.SPECIFICATION_FOR is not supported in SPDX-2.2"), (Relationship("SPDXRef-DOCUMENT", RelationshipType.REQUIREMENT_DESCRIPTION_FOR, "SPDXRef-Package"), - "RelationshipType.REQUIREMENT_DESCRIPTION_FOR is not supported for SPDX versions below SPDX-2.3")]) + "RelationshipType.REQUIREMENT_DESCRIPTION_FOR is not supported in SPDX-2.2")]) def test_v2_3_only_types(relationship, expected_message): document: Document = document_fixture() - validation_message: List[ValidationMessage] = validate_relationship(relationship, document, "SPDX-2.2") + validation_message: List[ValidationMessage] = validate_relationship(relationship, "SPDX-2.2", document) expected = [ValidationMessage(expected_message, ValidationContext(element_type=SpdxElementType.RELATIONSHIP, diff --git a/tests/spdx/validation/test_snippet_validator.py b/tests/spdx/validation/test_snippet_validator.py index f6594d93d..90bd4aca1 100644 --- a/tests/spdx/validation/test_snippet_validator.py +++ b/tests/spdx/validation/test_snippet_validator.py @@ -10,17 +10,19 @@ # limitations under the License. from typing import List +from unittest import TestCase import pytest -from spdx.validation.snippet_validator import validate_snippet_within_document +from spdx.validation.snippet_validator import validate_snippet_within_document, validate_snippet from spdx.validation.validation_message import ValidationMessage, ValidationContext, SpdxElementType from tests.spdx.fixtures import document_fixture, snippet_fixture def test_valid_snippet(): snippet = snippet_fixture() - validation_messages: List[ValidationMessage] = validate_snippet_within_document(snippet, document_fixture()) + validation_messages: List[ValidationMessage] = validate_snippet_within_document(snippet, "SPDX-2.3", + document_fixture()) assert validation_messages == [] @@ -36,7 +38,8 @@ def test_valid_snippet(): "the first value of line_range must be less than or equal to the second, but is: (45, 23)") ]) def test_invalid_ranges(snippet_input, expected_message): - validation_messages: List[ValidationMessage] = validate_snippet_within_document(snippet_input, document_fixture()) + validation_messages: List[ValidationMessage] = validate_snippet_within_document(snippet_input, "SPDX-2.3", + document_fixture()) expected = ValidationMessage(expected_message, ValidationContext(spdx_id=snippet_input.spdx_id, @@ -45,3 +48,17 @@ def test_invalid_ranges(snippet_input, expected_message): full_element=snippet_input)) assert validation_messages == [expected] + + +def test_v2_2mandatory_fields(): + snippet = snippet_fixture(license_concluded=None, copyright_text=None) + + assert validate_snippet(snippet, "SPDX-2.3") == [] + + validation_messages: List[ValidationMessage] = validate_snippet(snippet, "SPDX-2.2") + + context = ValidationContext(spdx_id=snippet.spdx_id, element_type=SpdxElementType.SNIPPET, full_element=snippet) + mandatory_fields = ["license_concluded", "copyright_text"] + expected = [ValidationMessage(f"{field} is mandatory in SPDX-2.2", context) for field in mandatory_fields] + + TestCase().assertCountEqual(validation_messages, expected) diff --git a/tests/spdx/validation/test_spdx_id_validators.py b/tests/spdx/validation/test_spdx_id_validators.py index ee8536cba..bcf8745c1 100644 --- a/tests/spdx/validation/test_spdx_id_validators.py +++ b/tests/spdx/validation/test_spdx_id_validators.py @@ -24,8 +24,9 @@ snippets=[snippet_fixture(spdx_id="SPDXRef-Snippet1"), snippet_fixture(spdx_id="SPDXRef-Snippet2")], creation_info=creation_info_fixture( - external_document_refs=[external_document_ref_fixture(document_ref_id="DocumentRef-external"), - external_document_ref_fixture(document_ref_id="DocumentRef-1.2-ext")])) + external_document_refs=[ + external_document_ref_fixture(document_ref_id="DocumentRef-external"), + external_document_ref_fixture(document_ref_id="DocumentRef-1.2-ext")])) @pytest.mark.parametrize("spdx_id", ["SPDXRef-DOCUMENT", "SPDXRef-File1", "SPDXRef-1.3-3.7"]) @@ -62,6 +63,7 @@ def test_is_external_doc_ref_present_in_document(): assert is_external_doc_ref_present_in_document("DocumentRef-1.2-ext", DOCUMENT) assert not is_external_doc_ref_present_in_document("DocumentRef-External1", DOCUMENT) + def test_list_of_all_spdx_ids(): TestCase().assertCountEqual(get_list_of_all_spdx_ids(DOCUMENT), ["SPDXRef-DOCUMENT", "SPDXRef-File1", "SPDXRef-File2", "SPDXRef-Package1", @@ -98,7 +100,8 @@ def test_invalid_spdx_id(spdx_id, expected_messages): @pytest.mark.parametrize("spdx_id", - ["DocumentRef-external:SPDXRef-File", "SPDXRef-DOCUMENT", "SPDXRef-File1", "SPDXRef-Package1", "SPDXRef-Snippet1"]) + ["DocumentRef-external:SPDXRef-File", "SPDXRef-DOCUMENT", "SPDXRef-File1", "SPDXRef-Package1", + "SPDXRef-Snippet1"]) def test_valid_spdx_id_with_check_document(spdx_id): validation_messages = validate_spdx_id(spdx_id, DOCUMENT, check_document=True) assert validation_messages == [] @@ -118,5 +121,6 @@ def test_valid_spdx_id_with_check_files(spdx_id): def test_invalid_spdx_id_with_check_files(): validation_messages = validate_spdx_id("SPDXRef-Package1", DOCUMENT, check_files=True) - assert validation_messages == ['did not find the referenced spdx_id "SPDXRef-Package1" in the SPDX document\'s files'] + assert validation_messages == [ + 'did not find the referenced spdx_id "SPDXRef-Package1" in the SPDX document\'s files']