Skip to content

Commit

Permalink
add SPDX generation test
Browse files Browse the repository at this point in the history
This is to ensure that both the new and old versions
of the SPDX writers satisfy the same tests. This uses an
Image instance that was generated during the call of
"tern report -i golang:1.12-alpine"

Signed-off-by: Armin Tänzer <armin.taenzer@tngtech.com>
  • Loading branch information
armintaenzertng committed Jul 11, 2023
1 parent 9f80484 commit 0f1ff2c
Show file tree
Hide file tree
Showing 6 changed files with 92 additions and 5 deletions.
2 changes: 2 additions & 0 deletions tern/formats/spdx/spdxjson/generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

import json
import logging
import pickle

from tern.formats.spdx.spdx import SPDX
from tern.formats.spdx import spdx_common
Expand Down Expand Up @@ -158,6 +159,7 @@ def generate(self, image_obj_list, print_inclusive=False):
# images. Hence we will assume only one image is analyzed and the
# input is a list of length 1
image_obj = image_obj_list[0]

template = SPDX()
report = get_document_dict(image_obj, template)

Expand Down
4 changes: 2 additions & 2 deletions tern/formats/spdx_new/layer_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ def get_layer_dict(layer_obj: ImageLayer) -> Tuple[SpdxPackage, List[Relationshi
The analyzed files will go in a separate part of the document."""

comment = get_layer_package_comment(layer_obj)
verification_code = get_layer_verification_code(layer_obj)
verification_code = get_layer_verification_code(layer_obj) if layer_obj.files_analyzed else None

layer_licenses = get_layer_licenses(layer_obj)
license_info_from_files = []
Expand All @@ -128,7 +128,7 @@ def get_layer_dict(layer_obj: ImageLayer) -> Tuple[SpdxPackage, List[Relationshi
file_name=layer_obj.tar_file,
download_location=SpdxNone(),
files_analyzed=bool(layer_obj.files_analyzed),
verification_code=verification_code if bool(layer_obj.files_analyzed) else None,
verification_code=verification_code,
checksums=[get_layer_checksum(layer_obj)],
license_concluded=SpdxNoAssertion(),
license_declared=SpdxNoAssertion(),
Expand Down
5 changes: 2 additions & 3 deletions tern/formats/spdx_new/make_spdx_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
from tern.formats.spdx_new.constants import DOCUMENT_ID, DOCUMENT_NAME, SPDX_VERSION, DATA_LICENSE, DOCUMENT_COMMENT, \
LICENSE_LIST_VERSION, CREATOR_NAME, DOCUMENT_NAME_SNAPSHOT, DOCUMENT_NAMESPACE_SNAPSHOT
from tern.formats.spdx_new.file_helpers import get_layer_files_list
from tern.formats.spdx_new.general_helpers import get_current_timestamp, get_uuid, get_image_spdxref
from tern.formats.spdx_new.general_helpers import get_current_timestamp, get_uuid
from tern.classes.image import Image
from tern.formats.spdx.spdx import SPDX
from tern.formats.spdx_new.file_helpers import get_files_list
Expand Down Expand Up @@ -51,7 +51,6 @@ def make_spdx_model(image_obj_list: List[Image]) -> Document:
data_license=DATA_LICENSE,
document_comment=DOCUMENT_COMMENT,
)
describes_relationship = Relationship(DOCUMENT_ID, RelationshipType.DESCRIBES, get_image_spdxref(image_obj))
packages = [get_image_dict(image_obj, template)]
image_layer_relationships = get_image_layer_relationships(image_obj)

Expand All @@ -69,7 +68,7 @@ def make_spdx_model(image_obj_list: List[Image]) -> Document:
creation_info=creation_info,
packages=packages,
files=files,
relationships=[describes_relationship] + image_layer_relationships + layer_file_relationships,
relationships=image_layer_relationships + layer_file_relationships,
extracted_licensing_info=extracted_licensing_info
)

Expand Down
Binary file added tests/golang_test_image.pkl
Binary file not shown.
Binary file added tests/large_tern_scan_image.pkl
Binary file not shown.
86 changes: 86 additions & 0 deletions tests/test_spdx_generation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import json
import os
import pickle
import unittest

from tern.classes.docker_image import DockerImage
from tern.formats.spdx.spdxjson.generator import SpdxJSON


class TestSPDXGeneration(unittest.TestCase):
test_package = {
"name": "alpine-keys",
"SPDXID": "SPDXRef-alpine-keys-2.1-r2",
"versionInfo": "2.1-r2",
"supplier": "Organization: Alpine Linux",
"downloadLocation": "NOASSERTION",
"filesAnalyzed": False,
"licenseConcluded": "NOASSERTION",
"licenseDeclared": "MIT",
"copyrightText": "NONE",
"externalRefs": [
{
"referenceCategory": "PACKAGE-MANAGER",
"referenceLocator": "pkg:apk/alpine/alpine-keys@2.1-r2?arch=x86_64",
"referenceType": "purl"
}
],
"comment": "alpine-keys:\n\twarning: No metadata for key: copyright\n\twarning: No metadata for key: download_url\n\twarning: No metadata for key: checksum\n\twarning: No metadata for key: pkg_licenses\n\twarning: No metadata for key: pkg_format\n\twarning: No metadata for key: src_name\n\twarning: No metadata for key: src_version\n"
}

test_describes_relationship = {
"spdxElementId": "SPDXRef-DOCUMENT",
"relatedSpdxElement": "SPDXRef-golang-1.12-alpine",
"relationshipType": "DESCRIBES"
}

test_contains_relationship = {
"spdxElementId": "SPDXRef-5216338b40",
"relatedSpdxElement": "SPDXRef-alpine-keys-2.1-r2",
"relationshipType": "CONTAINS"
}

test_has_prerequisite_relationship = {
"spdxElementId": "SPDXRef-3957f7032f",
"relatedSpdxElement": "SPDXRef-7306dca01e",
"relationshipType": "HAS_PREREQUISITE"
}

test_extracted_licensing_info = {
"extractedText": "MPL-2.0 GPL-2.0-or-later",
"licenseId": "LicenseRef-f30c02b"
}

def test_spdx_generation_from_pickled_image(self):
json_file_path = "spdx_test.json"
test_image_file_path = "large_tern_scan_image.pkl" # generated during "tern report -i golang:1.12-alpine"
with open(test_image_file_path, "rb") as f:
image = pickle.load(f)
image_list = [image]

json_as_string = SpdxJSON().generate(image_list)
with open(json_file_path, "w") as f:
f.write(json_as_string)

with open(json_file_path, "r") as f:
json_dict = json.load(f)
assert json_dict["SPDXID"] == "SPDXRef-DOCUMENT"
assert json_dict["spdxVersion"] == "SPDX-2.2"
assert len(json_dict["packages"]) == 21
assert self.test_package in json_dict["packages"]
assert len(json_dict["relationships"]) == 25
assert self.test_describes_relationship in json_dict["relationships"]
assert self.test_contains_relationship in json_dict["relationships"]
assert self.test_has_prerequisite_relationship in json_dict["relationships"]
assert len(json_dict["hasExtractedLicensingInfos"]) == 4
assert self.test_extracted_licensing_info in json_dict["hasExtractedLicensingInfos"]

os.remove(json_file_path)


def test_spdx_generation_from_docker_image(self):
docker_image = DockerImage('vmware/tern@sha256:20b32a9a20752aa1ad7582c6'
'67704fda9f004cc4bfd8601fac7f2656c7567bb4')

json_as_string = SpdxJSON().generate([docker_image])
i = 0

0 comments on commit 0f1ff2c

Please sign in to comment.