diff --git a/src/spdx_tools/spdx/validation/package_validator.py b/src/spdx_tools/spdx/validation/package_validator.py index 25cd6147f..37c74a394 100644 --- a/src/spdx_tools/spdx/validation/package_validator.py +++ b/src/spdx_tools/spdx/validation/package_validator.py @@ -4,9 +4,10 @@ from beartype.typing import List, Optional -from spdx_tools.spdx.model import Document, File, Package, Relationship, RelationshipType +from spdx_tools.spdx.model import Actor, ActorType, Document, File, Package, Relationship, RelationshipType from spdx_tools.spdx.model.relationship_filters import filter_by_type_and_origin, filter_by_type_and_target from spdx_tools.spdx.spdx_element_utils import get_element_type_from_spdx_id +from spdx_tools.spdx.validation.actor_validator import validate_actor from spdx_tools.spdx.validation.checksum_validator import validate_checksums from spdx_tools.spdx.validation.external_package_ref_validator import validate_external_package_refs from spdx_tools.spdx.validation.license_expression_validator import ( @@ -121,6 +122,28 @@ def validate_package( for message in validate_url(homepage): validation_messages.append(ValidationMessage("homepage " + message, context)) + if isinstance(package.supplier, Actor): + if package.supplier.actor_type == ActorType.TOOL: + validation_messages.append( + ValidationMessage( + f"package supplier must not be of actor type TOOL, but is: {package.supplier}", + context, + ) + ) + else: + validation_messages.extend(validate_actor(package.supplier, package.spdx_id)) + + if isinstance(package.originator, Actor): + if package.originator.actor_type == ActorType.TOOL: + validation_messages.append( + ValidationMessage( + f"package originator must not be of actor type TOOL, but is: {package.originator}", + context, + ) + ) + else: + validation_messages.extend(validate_actor(package.originator, package.spdx_id)) + verification_code = package.verification_code if verification_code: if not package.files_analyzed: diff --git a/tests/spdx/validation/test_package_validator.py b/tests/spdx/validation/test_package_validator.py index d0516fff2..120c350ff 100644 --- a/tests/spdx/validation/test_package_validator.py +++ b/tests/spdx/validation/test_package_validator.py @@ -9,7 +9,7 @@ from spdx_tools.common.spdx_licensing import spdx_licensing from spdx_tools.spdx.constants import DOCUMENT_SPDX_ID -from spdx_tools.spdx.model import Relationship, RelationshipType, SpdxNoAssertion, SpdxNone +from spdx_tools.spdx.model import Actor, ActorType, Relationship, RelationshipType, SpdxNoAssertion, SpdxNone from spdx_tools.spdx.validation.package_validator import validate_package, validate_package_within_document from spdx_tools.spdx.validation.validation_message import SpdxElementType, ValidationContext, ValidationMessage from tests.spdx.fixtures import document_fixture, file_fixture, package_fixture, package_verification_code_fixture @@ -154,3 +154,42 @@ def test_v2_2mandatory_fields(): expected = [ValidationMessage(f"{field} is mandatory in SPDX-2.2", context) for field in mandatory_fields] TestCase().assertCountEqual(validation_messages, expected) + + +@pytest.mark.parametrize( + "actor_field, actor_type_name", + [ + ("supplier", "supplier"), + ("originator", "originator"), + ], +) +def test_invalid_package_actor_tool(actor_field, actor_type_name): + tool_actor = Actor(actor_type=ActorType.TOOL, name="ToolName") + package = package_fixture(**{actor_field: tool_actor}) + validation_messages = validate_package(package, "SPDX-2.3") + + context = ValidationContext(spdx_id=package.spdx_id, element_type=SpdxElementType.PACKAGE, full_element=package) + expected = [ + ValidationMessage( + f"package {actor_type_name} must not be of actor type TOOL, but is: Tool: ToolName", + context, + ) + ] + + assert validation_messages == expected + + +@pytest.mark.parametrize( + "actor", + [ + Actor(actor_type=ActorType.PERSON, name="Jane Doe", email="jane@example.com"), + Actor(actor_type=ActorType.ORGANIZATION, name="Acme Corp"), + SpdxNoAssertion(), + None, + ], +) +def test_valid_package_supplier_and_originator(actor): + package = package_fixture(supplier=actor, originator=actor) + validation_messages = validate_package(package, "SPDX-2.3") + + assert validation_messages == []