Skip to content

Commit 6be6976

Browse files
committed
Invalid chars included in SPDX declared licenses
Tern was including commas and other invalid characters in SPDX license expressions which resulted in failed validation for generated SPDX docs. This commit removes the inappropriate characters and replaces them with valid ones (i.e. swapping `&` for `and`) before checking if a license expression is valid. It also updates the related function descriptions and comments for clarity. Fixes: #1223 Signed-off-by: Rose Judge <[email protected]>
1 parent c4b3508 commit 6be6976

File tree

5 files changed

+28
-15
lines changed

5 files changed

+28
-15
lines changed

tern/formats/spdx/spdx_common.py

+15-9
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,10 @@ def get_license_ref(license_string):
4646
return 'LicenseRef-' + get_string_id(license_string)
4747

4848
def is_spdx_license_expression(license_data):
49-
'''Return True if the license is a valid SPDX license expression, else
50-
return False'''
49+
'''Given a license string, replace common invalid SPDX license characters before
50+
checking if the string is a valid SPDX license expression. Return True/False
51+
and also return the updated license expression string.
52+
If case of error, return False with a blank string.'''
5153
licensing = get_spdx_licensing()
5254
not_allowed = [',', ';', '/', '&']
5355
if any(x in license_data for x in not_allowed):
@@ -57,18 +59,22 @@ def is_spdx_license_expression(license_data):
5759
license_data = license_data.replace(';', '.')
5860
license_data = license_data.replace('&', 'and')
5961
try:
60-
return licensing.validate(license_data).errors == []
62+
return licensing.validate(license_data).errors == [], license_data
6163
# Catch any of the other invalid license chars here
6264
except AttributeError:
63-
return False
65+
return False, ''
6466

6567
def get_package_license_declared(package_license_declared):
66-
'''Determines if the declared license string for a package or file is a
67-
valid SPDX license expression using the license_expression library. If not,
68-
returns the SPDX LicenseRef or NONE if the string is blank.'''
68+
'''After substituting common invalid SPDX license characters using
69+
the is_spdx_license_expression() function, determines if the declared
70+
license string for a package or file is a valid SPDX license expression.
71+
If license expression is valid after substitutions, return the updated string.
72+
If not, return the LicenseRef of the original declared license expression
73+
passed in to the function. If a blank string is passed in, return `NONE`.'''
6974
if package_license_declared:
70-
if is_spdx_license_expression(package_license_declared):
71-
return package_license_declared
75+
valid_spdx, license_expression = is_spdx_license_expression(package_license_declared)
76+
if valid_spdx:
77+
return license_expression
7278
return get_license_ref(package_license_declared)
7379
return 'NONE'
7480

tern/formats/spdx/spdxjson/image_helpers.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ def get_image_extracted_licenses(image_obj):
3434
unique_licenses.add(", ".join(package.pkg_licenses))
3535
extracted_texts = []
3636
for lic in list(unique_licenses):
37-
if not spdx_common.is_spdx_license_expression(lic):
37+
valid_spdx, _ = spdx_common.is_spdx_license_expression(lic)
38+
if not valid_spdx:
3839
extracted_texts.append(json_formats.get_extracted_text_dict(
3940
extracted_text=lic, license_ref=spdx_common.get_license_ref(
4041
lic)))

tern/formats/spdx/spdxjson/layer_helpers.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@ def get_layer_extracted_licenses(layer_obj):
3939
unique_licenses.add(package.pkg_license)
4040
extracted_texts = []
4141
for lic in list(unique_licenses):
42-
if not spdx_common.is_spdx_license_expression(lic):
42+
valid_spdx, _ = spdx_common.is_spdx_license_expression(lic)
43+
if not valid_spdx:
4344
extracted_texts.append(json_formats.get_extracted_text_dict(
4445
extracted_text=lic, license_ref=spdx_common.get_license_ref(
4546
lic)))

tern/formats/spdx/spdxjson/package_helpers.py

+5-2
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@ def get_source_package_dict(package, template):
4949
mapping['PackageCopyrightText'] else 'NONE',
5050
'comment': json_formats.source_package_comment
5151
}
52-
5352
return package_dict
5453

5554

@@ -60,6 +59,10 @@ def get_package_dict(package, template):
6059
mapping = package.to_dict(template)
6160
supplier_str = 'Organization: ' + mapping['PackageSupplier']
6261
pkg_ref, _ = spdx_common.get_package_spdxref(package)
62+
# Define debian licenses from copyright text as one license
63+
declared_lic = mapping['PackageLicenseDeclared']
64+
if package.pkg_format == 'deb':
65+
declared_lic = ', '.join(package.pkg_licenses)
6366
package_dict = {
6467
'name': mapping['PackageName'],
6568
'SPDXID': pkg_ref,
@@ -71,7 +74,7 @@ def get_package_dict(package, template):
7174
'filesAnalyzed': False, # always false for packages
7275
'licenseConcluded': 'NOASSERTION', # always NOASSERTION
7376
'licenseDeclared': spdx_common.get_package_license_declared(
74-
mapping['PackageLicenseDeclared']),
77+
declared_lic),
7578
'copyrightText': mapping['PackageCopyrightText'] if
7679
mapping['PackageCopyrightText'] else 'NONE',
7780
}

tern/formats/spdx/spdxtagvalue/image_helpers.py

+4-2
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,8 @@ def get_image_packages_license_block(image_obj):
6060
if package.pkg_licenses:
6161
licenses.add(", ".join(package.pkg_licenses))
6262
for lic in licenses:
63-
if not spdx_common.is_spdx_license_expression(lic):
63+
valid_expression, _ = spdx_common.is_spdx_license_expression(lic)
64+
if not valid_expression:
6465
block += spdx_formats.license_id.format(
6566
license_ref=spdx_common.get_license_ref(lic)) + '\n'
6667
block += spdx_formats.extracted_text.format(orig_license=lic) + '\n'
@@ -78,7 +79,8 @@ def get_image_file_license_block(image_obj):
7879
for lic in spdx_common.get_layer_licenses(layer):
7980
licenses.add(lic)
8081
for lic in licenses:
81-
if not spdx_common.is_spdx_license_expression(lic):
82+
valid_expression, _ = spdx_common.is_spdx_license_expression(lic)
83+
if not valid_expression:
8284
block += spdx_formats.license_id.format(
8385
license_ref=spdx_common.get_license_ref(lic)) + '\n'
8486
block += spdx_formats.extracted_text.format(orig_license=lic) + '\n'

0 commit comments

Comments
 (0)