Skip to content

Commit

Permalink
works with spdx tools-python v0.8.0
Browse files Browse the repository at this point in the history
Signed-off-by: Jeffrey Otterson <otterson@yahoo.com>
  • Loading branch information
jotterson committed Aug 12, 2023
1 parent 5bf8f11 commit e3d2eee
Show file tree
Hide file tree
Showing 8 changed files with 158 additions and 178 deletions.
9 changes: 8 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Released as part of my CS6767 Cybersecurity Practicum.
I took a problem that made me nervous at work and designed and implemented software to help mitigate this problem.
See the paper at [jotterson6_cs6727_project_report_20211212.docx-compressed.pdf](jotterson6_cs6727_project_report_20211212.docx-compressed.pdf)

# v 1.1.0 2023-xx-xx Support SPDX tools-python v0.7.x
# v 1.1.0 2023-06-11 Support SPDX tools-python v0.7.x

Support for latest SPDX tools-python, and, in theory, SPDX version 2.3.

Expand All @@ -15,3 +15,10 @@ more than one 'checksum' and more than one 'file type'.

JSON storage mode is selected based on specified command line arguments file extension. If you specify a file name
that ends with '.json' then JSON format will be used, else SPDX tagged-value format will be used.

# V 1.2.0 2023-08-12 Support SPDX tools-python V0.8.0

Support for latest SPDX tools-python v0.8.0

Minimally tested with zip package inputs.

47 changes: 31 additions & 16 deletions create-sbom.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,10 @@
from zipfile import ZipFile

import signature_utilities
from spdx.checksum import Checksum, ChecksumAlgorithm
from spdx_tools.spdx.model.checksum import Checksum, ChecksumAlgorithm
from spdx_tools.spdx.model.relationship import RelationshipType, Relationship

from spdx_utilities import \
add_checksum_to_spdx_file, \
add_signature_to_spdx_document, \
get_digital_signature_from_spdx_document, \
guess_spdx_file_type_from_data, \
Expand All @@ -52,7 +53,7 @@
write_spdx_file
from validation_utilities import files_in_dir

HASH_NAMES = ['SHA1', 'SHA256']
ALGORITHMS = [ChecksumAlgorithm.SHA1, ChecksumAlgorithm.SHA256]
spdx_id_counter = 0


Expand Down Expand Up @@ -81,22 +82,29 @@ def package_path_to_spdx_doc(args):
full_path = f'{package_path}/{file}'
if args.flat:
_, file = os.path.split(file)
spdx_file = new_spdx_file(filename=file, spdx_id=new_spdx_id())

if args.file_comment is not None:
spdx_file.comment = args.file_comment
comment = args.file_comment
else:
spdx_file.comment = f'found during scan of {package_name}'
for hash_name in HASH_NAMES:
hasher = hashlib.new(hash_name)
comment = f'found during scan of {package_name}'
checksums = []
for algorithm in ALGORITHMS:
hasher = hashlib.new(str(algorithm).split('.')[1])
with open(full_path, 'rb') as fh:
while True:
block = fh.read(64*1024)
if not block:
break
hasher.update(block)
add_checksum_to_spdx_file(spdx_file, hash_name.upper(), hasher.hexdigest())
checksums.append(Checksum(algorithm, hasher.hexdigest()))

spdx_file = new_spdx_file(filename=file, spdx_id=new_spdx_id(), checksums=checksums, comment=comment)

set_spdx_file_type(spdx_file, full_path)
spdx_doc.add_file(spdx_file)
spdx_doc.relationships.append(Relationship(spdx_doc.creation_info.spdx_id,
RelationshipType.DESCRIBES,
spdx_file.spdx_id))
return spdx_doc


Expand All @@ -118,23 +126,30 @@ def package_zip_to_spdx_doc(args):
else:
filename = file
filename = './' + filename
spdx_file = new_spdx_file(filename=filename, spdx_id=new_spdx_id())

if args.file_comment is not None:
spdx_file.comment = args.comment
comment = args.file_comment
else:
spdx_file.comment = f'found during scan of {package_name}'
comment = f'found during scan of {package_name}'
checksums = []
data = zipfile.read(file)
for hash_name in HASH_NAMES:
hasher = hashlib.new(hash_name)
for algorithm in ALGORITHMS:
hasher = hashlib.new(str(algorithm).split('.')[1])
hasher.update(data)
add_checksum_to_spdx_file(spdx_file, hash_name.upper(), hasher.hexdigest())
checksums.append(Checksum(algorithm, hasher.hexdigest()))

spdx_file = new_spdx_file(filename=filename, spdx_id=new_spdx_id(), checksums=checksums, comment=comment)

spdx_file_types = guess_spdx_file_type_from_extension(file)
if spdx_file_types is None:
spdx_file_types = guess_spdx_file_type_from_data(data)
if spdx_file_types is None or len(spdx_file_types) == 0:
logging.error(f'bad... {file}')
spdx_file.file_types = spdx_file_types
spdx_doc.add_file(spdx_file)
spdx_doc.files.append(spdx_file)
spdx_doc.relationships.append(Relationship(spdx_doc.creation_info.spdx_id,
RelationshipType.DESCRIBES,
spdx_file.spdx_id))
return spdx_doc


Expand Down
49 changes: 27 additions & 22 deletions edit-sbom.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,17 +29,22 @@
import argparse
import logging

import license_expression
from asciimatics.widgets import Button, Divider, DropdownList, Frame, Layout, MultiColumnListBox, Text, Widget
from asciimatics.scene import Scene
from asciimatics.screen import Screen
from asciimatics.exceptions import NextScene, ResizeScreenError, StopApplication

from license_expression import get_spdx_licensing, LicenseExpression

import signature_utilities
import spdx_utilities
from spdx_utilities import add_signature_to_spdx_document, read_spdx_file, serialize_spdx_doc, write_spdx_file
from spdx.checksum import ChecksumAlgorithm
from spdx.license import License
from spdx.utils import NoAssert, SPDXNone
from spdx_utilities import (add_signature_to_spdx_document, get_specified_checksum,
read_spdx_file, serialize_spdx_doc, write_spdx_file)
from spdx_tools.spdx.model.checksum import ChecksumAlgorithm
from spdx_tools.spdx.model.spdx_no_assertion import SpdxNoAssertion
from spdx_tools.spdx.model.spdx_none import SpdxNone
from spdx_tools.spdx.model.relationship import RelationshipType, Relationship


class SpdxFileFilesAsListModel(object):
Expand Down Expand Up @@ -93,18 +98,18 @@ def get_current_file_form_data(self):
if self.current_file is None:
data = {'name': '', 'comment': '', 'spdx_id': '', 'copyright': '', 'notice': ''}
else:
copyright_text = self.current_file.copyright
copyright_text = self.current_file.copyright_text
if copyright_text is None:
copyright_text = 'NONE'
elif isinstance(copyright_text, NoAssert):
elif isinstance(copyright_text, SpdxNoAssertion):
copyright_text = 'NOASSERTION'

if isinstance(self.current_file.conc_lics, NoAssert):
if isinstance(self.current_file.license_concluded, SpdxNoAssertion):
license_text = 'NOASSERTION'
elif isinstance(self.current_file.conc_lics, SPDXNone):
elif isinstance(self.current_file.license_concluded, SpdxNoAssertion):
license_text = 'NONE'
elif isinstance(self.current_file.conc_lics, License):
license_text = self.current_file.conc_lics.identifier
elif isinstance(self.current_file.license_concluded, LicenseExpression):
license_text = str(self.current_file.license_concluded)
else:
license_text = 'NOASSERTION'

Expand All @@ -115,14 +120,13 @@ def get_current_file_form_data(self):
'license': license_text,
'notice': self.current_file.notice,
}
for hash_name in ['SHA1', 'SHA256']:
algo = ChecksumAlgorithm.checksum_algorithm_from_string(hash_name)
hash_value = self.current_file.get_checksum(algo)
if hash_value is not None:
value = hash_value.value
for algorithm in [ChecksumAlgorithm.SHA1, ChecksumAlgorithm.SHA256]:
checksum = get_specified_checksum(self.current_file.checksums, algorithm)
if checksum is not None:
value = checksum.value
else:
value = ''
data[hash_name.lower()] = value
data[str(algorithm).split('.')[1]] = value
return data

def set_current_file(self, spdx_id):
Expand All @@ -147,22 +151,23 @@ def update_current_file(self, data):
self.current_file.comment = comment
copyright_text = data.get('copyright') or 'NOASSERTION'
if copyright_text.upper() == 'NOASSERTION':
self.current_file.copyright = NoAssert()
self.current_file.copyright = SpdxNoAssertion()
elif copyright_text.upper() == 'NONE' or len(copyright_text) == 0:
self.current_file.copyright = SPDXNone
self.current_file.copyright = SpdxNone()
else:
self.current_file.copyright = copyright_text
notice = data.get('notice') or ''
if len(notice) == 0:
notice = None
self.current_file.notice = notice
license_text = data.get('license') or 'NOASSERTION'
if license_text == str(NoAssert()):
self.current_file.conc_lics = NoAssert()
if license_text == str(SpdxNoAssertion()):
self.current_file.conc_lics = SpdxNoAssertion()
elif license_text == 'NONE' or len(license_text) == 0:
self.current_file.conc_lics = SPDXNone()
self.current_file.license_concluded = SpdxNone()
else:
self.current_file.conc_lics = License.from_identifier(license_text)
new_license = license_expression.get_spdx_licensing().parse(license_text)
self.current_file.license_concluded = new_license

def delete_file(self, file):
"""
Expand Down
8 changes: 4 additions & 4 deletions merge-and-test.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@

import signature_utilities
import spdx_utilities
from spdx.license import License
from spdx.file import FileType
from spdx.checksum import ChecksumAlgorithm
from license_expression import get_spdx_licensing, LicenseExpression
from spdx_tools.spdx.model.file import FileType
from spdx_tools.spdx.model.checksum import ChecksumAlgorithm

CHECKSUM_ALGORITHM = ChecksumAlgorithm.SHA256

Expand Down Expand Up @@ -139,7 +139,7 @@ def main():
warnings += 1
else:
ideal_file = ideal_file_dict['file']
if isinstance(ideal_file.conc_lics, License):
if isinstance(ideal_file.license_concluded, LicenseExpression):
ideal_file_sha256 = ideal_file.get_checksum(CHECKSUM_ALGORITHM).value
build_file_sha256 = build_file.get_checksum(CHECKSUM_ALGORITHM).value
if ideal_file_sha256 == build_file_sha256:
Expand Down
19 changes: 9 additions & 10 deletions merge-by-sha256.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@

import signature_utilities
import spdx_utilities
from spdx.checksum import ChecksumAlgorithm
from spdx_tools.spdx.model.checksum import ChecksumAlgorithm

CHECKSUM_ALGORITHM = ChecksumAlgorithm.SHA256

Expand Down Expand Up @@ -124,33 +124,32 @@ def main():

merge_files_by_sha256 = {}
for file in merge_files:
sha256 = file.get_checksum(CHECKSUM_ALGORITHM)
sha256 = spdx_utilities.get_specified_checksum(file.checksums, CHECKSUM_ALGORITHM)
merge_files_by_sha256[sha256.value] = file

for source_file in source_files:
sha256 = source_file.get_checksum(CHECKSUM_ALGORITHM)
sha256 = spdx_utilities.get_specified_checksum(source_file.checksums, CHECKSUM_ALGORITHM)
if sha256 is not None:
merge_file = merge_files_by_sha256.get(sha256.value)
if merge_file is not None:
_, source_file_name = os.path.split(source_file.name)
_, merge_file_name = os.path.split(merge_file.name)
source_file.comment = merge_file.comment
if source_file_name != merge_file_name:
logging.warning('File names do not match but sha does: {} should be {}'.format(source_file_name,
merge_file_name))
if source_file.comment is None:
source_file.comment = ''
source_file.comment += 'name is {}'.format(merge_file_name)
warnings += 1
else:
successes += 1
source_file.file_types = merge_file.file_types
# source_file.chk_sums = merge_file.chk_sums # not merging hashes -- better not need to!
source_file.conc_lics = merge_file.conc_lics
source_file.licenses_in_file = merge_file.licenses_in_file
source_file.license_concluded = merge_file.license_concluded
source_file.license_info_in_file = merge_file.license_info_in_file
source_file.license_comment = merge_file.license_comment
source_file.copyright = merge_file.copyright
source_file.copyright_text = merge_file.copyright_text
source_file.comment = merge_file.comment
source_file.notice = merge_file.notice
source_file.contributors = merge_file.contributors
source_file.attribution_texts = merge_file.attribution_texts

if successes > 0:
logging.info('{} spdx files merged using without error.'.format(successes))
Expand Down
11 changes: 6 additions & 5 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
ply~=3.11
rdflib~=6.3
xmltodict~=0.13
PyYAML~=6.0
click~=8.1
asciimatics~=1.14
click~=8.1
cryptography~=41.0
spdx-tools~=0.7
license_expression~=30.1
ply~=3.11
rdflib~=6.3
spdx-tools~=0.8.0
xmltodict~=0.13
Loading

0 comments on commit e3d2eee

Please sign in to comment.