Skip to content

Commit

Permalink
Export specific format versions (SPDX)
Browse files Browse the repository at this point in the history
This is a prototype for the ability to export in different versions of SPDX.
It fixes tern-tools#1211

Signed-off-by: Marc-Etienne Vargenau <[email protected]>
  • Loading branch information
vargenau committed Mar 23, 2023
1 parent 62507ed commit 8ab46ab
Show file tree
Hide file tree
Showing 6 changed files with 35 additions and 14 deletions.
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -325,12 +325,26 @@ Many compliance tools are compatible with SPDX. Tern follows the [SPDX specifica
```
$ tern report -f spdxtagvalue -i golang:1.12-alpine -o spdx.txt
```
By default, the report will be in SPDX version 2.2 (ISO SPDX).

The following syntax will output SPDX 2.3:
```
$ tern report -f [email protected] -i golang:1.12-alpine -o spdx.txt
```


## SPDX JSON Format<a name="report-spdxjson">
The SPDX JSON format contains the same information that an SPDX Tag-value document does. The only difference between these two formats is the way the information is represented. The 'spdxjson' format represents the container information as a collection of key-value pairs. In some cases, the SPDX JSON format may be more interoperable between cloud native compliance tools.
```
$ tern report -f spdxjson -i golang:1.12-alpine -o spdx.json
```
By default, the report will be in SPDX version 2.2 (ISO SPDX).

The following syntax will output SPDX 2.3:
```
$ tern report -f [email protected] -i golang:1.12-alpine -o spdx.json
```


## CycloneDX JSON Format<a name="report-cyclonedxjson">
[OWASP CycloneDX](https://cyclonedx.org/) is a lightweight software bill of materials standard designed for use in application security contexts and supply chain component analysis. The National Telecommunications and Information Administration (NTIA) [recognizes CycloneDX](https://www.ntia.gov/files/ntia/publications/sbom_options_and_decision_points_20210427-1.pdf) as one of three valid SBOM formats that satisfies the minimum viable requirements for an SBOM in accordance with President Biden's [Executive Order on Improving the Nation's Cybersecurity](https://www.whitehouse.gov/briefing-room/presidential-actions/2021/05/12/executive-order-on-improving-the-nations-cybersecurity/).
Expand Down
2 changes: 1 addition & 1 deletion tern/formats/spdx/spdxjson/formats.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@


# document level strings
spdx_version = 'SPDX-2.2'
spdx_version = 'SPDX-'
data_license = 'CC0-1.0'
spdx_id = 'SPDXRef-DOCUMENT'
document_name = 'Tern report for {image_name}'
Expand Down
8 changes: 4 additions & 4 deletions tern/formats/spdx/spdxjson/generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,11 @@ def get_document_namespace_snapshot(timestamp):
timestamp=timestamp, uuid=spdx_common.get_uuid())


def get_document_dict(image_obj, template):
def get_document_dict(image_obj, template, spdxv):
'''Return document info as a dictionary'''
docu_dict = {
'SPDXID': json_formats.spdx_id,
'spdxVersion': json_formats.spdx_version,
'spdxVersion': json_formats.spdx_version+spdxv,
'creationInfo': {
'created': json_formats.created.format(
timestamp=spdx_common.get_timestamp()),
Expand Down Expand Up @@ -140,7 +140,7 @@ def get_document_dict_snapshot(layer_obj, template):


class SpdxJSON(generator.Generate):
def generate(self, image_obj_list, print_inclusive=False):
def generate(self, image_obj_list, print_inclusive=False, spdxv='2.2'):
'''Generate an SPDX document
WARNING: This assumes that the list consists of one image or the base
image and a stub image, in which case, the information in the stub
Expand All @@ -159,7 +159,7 @@ def generate(self, image_obj_list, print_inclusive=False):
# input is a list of length 1
image_obj = image_obj_list[0]
template = SPDX()
report = get_document_dict(image_obj, template)
report = get_document_dict(image_obj, template, spdxv)

return json.dumps(report)

Expand Down
2 changes: 1 addition & 1 deletion tern/formats/spdx/spdxtagvalue/formats.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
block_text = '<text>\n{message}\n</text>'

# document level strings
spdx_version = 'SPDXVersion: SPDX-2.2'
spdx_version = 'SPDXVersion: SPDX-'
data_license = 'DataLicense: CC0-1.0'
spdx_id = 'SPDXID: SPDXRef-DOCUMENT'
document_name = 'DocumentName: Tern report for {image_name}'
Expand Down
8 changes: 4 additions & 4 deletions tern/formats/spdx/spdxtagvalue/generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@ def get_document_namespace(image_obj):
uuid=spdx_common.get_uuid())


def get_document_block(image_obj):
def get_document_block(image_obj, spdxv):
'''Return document related SPDX tag-values'''
block = spdx_formats.spdx_version + '\n'
block = spdx_formats.spdx_version + spdxv + '\n'
block = block + spdx_formats.data_license + '\n'
block = block + spdx_formats.spdx_id + '\n'
block = block + spdx_formats.document_name.format(
Expand All @@ -51,7 +51,7 @@ def get_document_block(image_obj):


class SpdxTagValue(generator.Generate):
def generate(self, image_obj_list, print_inclusive=False):
def generate(self, image_obj_list, print_inclusive=False, spdxv='2.2'):
'''Generate an SPDX document
WARNING: This assumes that the list consists of one image or the base
image and a stub image, in which case, the information in the stub
Expand Down Expand Up @@ -134,7 +134,7 @@ def generate(self, image_obj_list, print_inclusive=False):

# first part is the document tag-value
# this doesn't change at all
report += get_document_block(image_obj) + '\n'
report += get_document_block(image_obj, spdxv) + '\n'

# this is the image part
# this will bring in layer and package information
Expand Down
15 changes: 11 additions & 4 deletions tern/report/report.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,20 @@ def clean_image_tars(image_obj):

def generate_report(args, *images):
'''Generate a report based on the command line options'''
args.spdxv = '2.2'
if args.report_format and (args.report_format == '[email protected]'):
args.report_format = 'spdxtagvalue'
args.spdxv = '2.3'
if args.report_format and (args.report_format == '[email protected]'):
args.report_format = 'spdxjson'
args.spdxv = '2.3'
if args.report_format:
return generate_format(
images, args.report_format, args.print_inclusive)
return generate_format(images, 'default', args.print_inclusive)
images, args.report_format, args.print_inclusive, args.spdxv)
return generate_format(images, 'default', args.print_inclusive, args.spdxv)


def generate_format(images, format_string, print_inclusive):
def generate_format(images, format_string, print_inclusive, spdxv):
'''Generate a report in the format of format_string given one or more
image objects. Here we will load the required module and run the generate
function to get back a report'''
Expand All @@ -53,7 +60,7 @@ def generate_format(images, format_string, print_inclusive):
name=format_string,
invoke_on_load=True,
)
return mgr.driver.generate(images, print_inclusive)
return mgr.driver.generate(images, print_inclusive, spdxv)
except NoMatches:
return None

Expand Down

0 comments on commit 8ab46ab

Please sign in to comment.