Skip to content

Commit 85b480a

Browse files
[issue-744] implement validation of external license references
Signed-off-by: Armin Tänzer <armin.taenzer@tngtech.com>
1 parent ca72624 commit 85b480a

File tree

2 files changed

+69
-2
lines changed

2 files changed

+69
-2
lines changed

src/spdx_tools/spdx/validation/license_expression_validator.py

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
from spdx_tools.common.spdx_licensing import spdx_licensing
99
from spdx_tools.spdx.model import Document, SpdxNoAssertion, SpdxNone
10+
from spdx_tools.spdx.validation.spdx_id_validators import is_external_doc_ref_present_in_document
1011
from spdx_tools.spdx.validation.validation_message import SpdxElementType, ValidationContext, ValidationMessage
1112

1213

@@ -42,7 +43,36 @@ def validate_license_expression(
4243
license_ref_ids: List[str] = [license_ref.license_id for license_ref in document.extracted_licensing_info]
4344

4445
for non_spdx_token in spdx_licensing.validate(license_expression).invalid_symbols:
45-
if non_spdx_token not in license_ref_ids:
46+
if ":" in non_spdx_token:
47+
split_token: List[str] = non_spdx_token.split(":")
48+
if len(split_token) != 2:
49+
validation_messages.append(
50+
ValidationMessage(
51+
f"Too many colons in license reference: {non_spdx_token}. "
52+
"A license reference must only contain a single colon to "
53+
"separate an external document reference from the license reference.",
54+
context,
55+
)
56+
)
57+
else:
58+
if not split_token[1].startswith("LicenseRef-"):
59+
validation_messages.append(
60+
ValidationMessage(
61+
f'A license reference must start with "LicenseRef-", but is: {split_token[1]} '
62+
f"in external license reference {non_spdx_token}.",
63+
context,
64+
)
65+
)
66+
if not is_external_doc_ref_present_in_document(split_token[0], document):
67+
validation_messages.append(
68+
ValidationMessage(
69+
f'Did not find the external document reference "{split_token[0]}" in the SPDX document. '
70+
f"From the external license reference {non_spdx_token}.",
71+
context,
72+
)
73+
)
74+
75+
elif non_spdx_token not in license_ref_ids:
4676
validation_messages.append(
4777
ValidationMessage(
4878
f"Unrecognized license reference: {non_spdx_token}. license_expression must only use IDs from the "

tests/spdx/validation/test_license_expression_validator.py

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,10 @@
1515
validate_license_expressions,
1616
)
1717
from spdx_tools.spdx.validation.validation_message import SpdxElementType, ValidationContext, ValidationMessage
18-
from tests.spdx.fixtures import document_fixture, extracted_licensing_info_fixture
18+
from tests.spdx.fixtures import document_fixture, external_document_ref_fixture, extracted_licensing_info_fixture
1919

2020
FIXTURE_LICENSE_ID = extracted_licensing_info_fixture().license_id
21+
EXTERNAL_DOCUMENT_ID = external_document_ref_fixture().document_ref_id
2122

2223

2324
@pytest.mark.parametrize(
@@ -26,6 +27,7 @@
2627
"MIT",
2728
FIXTURE_LICENSE_ID,
2829
f"GPL-2.0-only with GPL-CC-1.0 and {FIXTURE_LICENSE_ID} with 389-exception or Beerware",
30+
f"{EXTERNAL_DOCUMENT_ID}:LicenseRef-007",
2931
],
3032
)
3133
def test_valid_license_expression(expression_string):
@@ -136,3 +138,38 @@ def test_invalid_license_expression_with_invalid_exceptions(expression_string, e
136138
expected_messages = [ValidationMessage(expected_message, context)]
137139

138140
assert validation_messages == expected_messages
141+
142+
143+
@pytest.mark.parametrize(
144+
"expression_string, expected_message",
145+
[
146+
(
147+
f"{EXTERNAL_DOCUMENT_ID}:LicenseRef-007:4",
148+
f"Too many colons in license reference: {EXTERNAL_DOCUMENT_ID}:LicenseRef-007:4. "
149+
"A license reference must only contain a single colon to "
150+
"separate an external document reference from the license reference.",
151+
),
152+
(
153+
f"{EXTERNAL_DOCUMENT_ID}:unknown_license",
154+
'A license reference must start with "LicenseRef-", but is: unknown_license '
155+
f"in external license reference {EXTERNAL_DOCUMENT_ID}:unknown_license.",
156+
),
157+
(
158+
"DocumentRef-unknown:LicenseRef-1",
159+
'Did not find the external document reference "DocumentRef-unknown" in the SPDX document. '
160+
"From the external license reference DocumentRef-unknown:LicenseRef-1.",
161+
),
162+
],
163+
)
164+
def test_invalid_license_expression_with_external_reference(expression_string, expected_message):
165+
document: Document = document_fixture()
166+
license_expression: LicenseExpression = spdx_licensing.parse(expression_string)
167+
parent_id = "SPDXRef-File"
168+
context = ValidationContext(
169+
parent_id=parent_id, element_type=SpdxElementType.LICENSE_EXPRESSION, full_element=license_expression
170+
)
171+
172+
validation_messages: List[ValidationMessage] = validate_license_expression(license_expression, document, parent_id)
173+
expected_messages = [ValidationMessage(expected_message, context)]
174+
175+
assert validation_messages == expected_messages

0 commit comments

Comments
 (0)