Skip to content

Commit

Permalink
spdx: Handle reporting for empty license metadata
Browse files Browse the repository at this point in the history
Currently, if no license metadata is found (i.e. debian-based images)
Tern does not generate valid SPDX. An empty license field still reports
as "LicenseRef-". According to the 2.1 spec, if information about the
license is unknown, the value should be NOASSERTION.

This commit adds a few checks in
tern/formats/spdx/spdxtagvalue/generator.py to make sure that a license
value exists before trying to report the license information.

It also moves the get_package_id functionality originally in
tern/classes/package.py to a format in tern/formats/spdx/formats.py as
package_id is a value only utilized by SPDX format reports. Since
the get_package_id functionality was moved out of classes, the test for
this function was removed from the test_class_package test file.

tern/formats/spdx/spdxtagvalue/generator.py was updated to pull the
package_id info from spdx formats.py and has additional manipulation
to handle the case when a debian package is reported in the form
[epoch:]upstream_version[-debian_revision]. The colon after the epoch
needs to be changed to '-' in order to validate the SPDX report.

Additionally, this commit wraps the PackageCopyrightText value in
<text></text> in the case that the copyright statement is more than one
line per guidelines from the 2.1 spec.

Finally, this commit makes a change to the logic inside
update_license_list() that gets rid of the dangling license block at
the end of the report if no licenses are available from the container
image metadata.

Resolves tern-tools#431

Signed-off-by: Rose Judge <rjudge@vmware.com>
  • Loading branch information
rnjudge authored and Nisha K committed Sep 5, 2019
1 parent 838b277 commit d68c533
Show file tree
Hide file tree
Showing 4 changed files with 19 additions and 16 deletions.
6 changes: 0 additions & 6 deletions tern/classes/package.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,9 +155,3 @@ def is_equal(self, other):
if value != other_pkg_dict[key]:
return False
return True

def get_package_id(self):
'''This method returns a string of the name and version for a package
represented as "name.version". This method might be helpful when working
with SPDX documents that require a unique package identifier.'''
return "{0}.{1}".format(self.name, self.version)
2 changes: 2 additions & 0 deletions tern/formats/spdx/formats.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

# basic strings
tag_value = '{tag}: {value}'
block_text = '<text>{message}</text>'

# document level strings
spdx_version = 'SPDXVersion: SPDX-2.1'
Expand All @@ -25,6 +26,7 @@

# Package level strings
package_comment = 'PackageComment: <text>{comment}</text>'
package_id = '{name}-{ver}'

# Relationship strings
contains = 'Relationship: {outer} CONTAINS {inner}'
Expand Down
24 changes: 17 additions & 7 deletions tern/formats/spdx/spdxtagvalue/generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,10 @@ def get_document_namespace(image_obj):

def get_package_spdxref(package_obj):
'''Given the package object, return an SPDX reference ID'''
return 'SPDXRef-{}'.format(package_obj.get_package_id())
return 'SPDXRef-{}'.format(
spdx_formats.package_id.format(
name=package_obj.name,
ver=package_obj.version).replace(':', '-', 1))


def get_layer_spdxref(layer_obj):
Expand Down Expand Up @@ -130,7 +133,7 @@ def update_license_list(license_list, license_string):
string is not in the list, add it'''
licenses = get_package_licenses(license_string)
for l in licenses:
if l not in license_list:
if l and l not in license_list:
license_list.append(l)


Expand All @@ -154,9 +157,9 @@ def get_license_block(license_list):
block = ''
for l in license_list:
block = block + spdx_formats.license_id.format(
license_ref=get_license_ref(l)) + '\n'
license_ref=get_license_ref(l) if l else 'NOASSERTION') + '\n'
block = block + spdx_formats.extracted_text.format(
orig_license=l) + '\n\n'
orig_license=l if l else 'NOASSERTION') + '\n\n'
return block


Expand Down Expand Up @@ -279,9 +282,16 @@ def generate(self, image_obj_list):
for package_obj in layer_obj.packages:
package_dict = package_obj.to_dict(template)
# update the PackageLicenseDeclared with a LicenseRef string
if 'PackageLicenseDeclared' in package_dict.keys():
package_dict['PackageLicenseDeclared'] = format_license(
package_obj.pkg_license)
# only if the license data exists
if ('PackageLicenseDeclared' in package_dict.keys() and
package_obj.pkg_license):
package_dict['PackageLicenseDeclared'] = \
format_license(package_obj.pkg_license)
if ('PackageCopyrightText' in package_dict.keys() and
package_obj.copyright):
package_dict['PackageCopyrightText'] = \
spdx_formats.block_text.format(
message=package_obj.copyright)
# collect all the individual licenses
update_license_list(licenses_found, package_obj.pkg_license)
report = report + get_main_block(
Expand Down
3 changes: 0 additions & 3 deletions tests/test_class_package.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,9 +121,6 @@ def testFill(self):
self.assertEqual(p.origins.origins[0].notices[2].message,
"No metadata for key: download_url")

def testGetPackageId(self):
self.assertEqual(self.p1.get_package_id(), 'p1.1.0')


if __name__ == '__main__':
unittest.main()

0 comments on commit d68c533

Please sign in to comment.