From 72780a48d830b29c5d8c85c27e9ddbf39c22b6f6 Mon Sep 17 00:00:00 2001 From: Meret Behrens Date: Mon, 28 Nov 2022 11:20:02 +0100 Subject: [PATCH] [issue-185] squash review commits Signed-off-by: Meret Behrens --- examples/write_tv.py | 8 ++-- spdx/checksum.py | 46 +++++++++++++------ spdx/cli_tools/parser.py | 6 +-- spdx/document.py | 12 ++--- spdx/file.py | 43 +++++++++--------- spdx/package.py | 45 +++++++++---------- spdx/parsers/jsonyamlxml.py | 12 ++--- spdx/parsers/jsonyamlxmlbuilders.py | 30 ++++++++----- spdx/parsers/lexers/tagvalue.py | 2 +- spdx/parsers/rdf.py | 20 ++++----- spdx/parsers/rdfbuilders.py | 46 ++++++++++--------- spdx/parsers/tagvaluebuilders.py | 26 +++-------- spdx/utils.py | 19 ++++---- spdx/writers/json.py | 1 - spdx/writers/jsonyamlxml.py | 12 +++-- spdx/writers/rdf.py | 8 ++-- spdx/writers/tagvalue.py | 2 +- tests/data/doc_parse/spdx-expected.json | 30 ++++++++----- tests/data/doc_write/json-simple-plus.json | 51 +++++++++++----------- tests/data/doc_write/json-simple.json | 20 ++++----- tests/data/formats/SPDXTagExample.tag | 4 +- tests/test_builder.py | 4 +- tests/test_checksum.py | 48 ++++++++++++++++++++ tests/test_document.py | 27 ++++++------ tests/test_jsonyamlxml_writer.py | 4 +- tests/test_package.py | 6 +-- tests/utils_test.py | 8 ++-- 27 files changed, 303 insertions(+), 237 deletions(-) create mode 100644 tests/test_checksum.py diff --git a/examples/write_tv.py b/examples/write_tv.py index 47c8cd494..3273b3b2d 100755 --- a/examples/write_tv.py +++ b/examples/write_tv.py @@ -15,7 +15,7 @@ from spdx.review import Review from spdx.package import Package from spdx.file import File, FileType - from spdx.checksum import Algorithm + from spdx.checksum import Checksum from spdx.utils import SPDXNone, NoAssert, UnKnown doc = Document() @@ -36,7 +36,7 @@ testfile1.type = FileType.BINARY testfile1.spdx_id = "TestFilet#SPDXRef-FILE" testfile1.comment = "This is a test file." - testfile1.chksum = Algorithm("SHA1", "c537c5d99eca5333f23491d47ededd083fefb7ad") + testfile1.chksum = Checksum("SHA1", "c537c5d99eca5333f23491d47ededd083fefb7ad") testfile1.conc_lics = License.from_identifier("BSD-2-Clause") testfile1.add_lics(License.from_identifier("BSD-2-Clause")) testfile1.copyright = SPDXNone() @@ -48,7 +48,7 @@ testfile2.type = FileType.SOURCE testfile2.spdx_id = "TestFile2#SPDXRef-FILE" testfile2.comment = "This is a test file." - testfile2.chksum = Algorithm("SHA1", "bb154f28d1cf0646ae21bb0bec6c669a2b90e113") + testfile2.chksum = Checksum("SHA1", "bb154f28d1cf0646ae21bb0bec6c669a2b90e113") testfile2.conc_lics = License.from_identifier("Apache-2.0") testfile2.add_lics(License.from_identifier("Apache-2.0")) testfile2.copyright = NoAssert() @@ -62,7 +62,7 @@ package.file_name = "twt.jar" package.spdx_id = 'TestPackage#SPDXRef-PACKAGE' package.download_location = "http://www.tagwritetest.test/download" - package.checksum = Algorithm("SHA1", "c537c5d99eca5333f23491d47ededd083fefb7ad") + package.checksum = Checksum("SHA1", "c537c5d99eca5333f23491d47ededd083fefb7ad") package.homepage = SPDXNone() package.verif_code = "4e3211c67a2d28fced849ee1bb76e7391b93feba" license_set = LicenseConjunction( diff --git a/spdx/checksum.py b/spdx/checksum.py index 121e58321..c17361818 100644 --- a/spdx/checksum.py +++ b/spdx/checksum.py @@ -10,10 +10,10 @@ # limitations under the License. import re from enum import Enum, auto +from typing import Optional - -class ChecksumAlgorithmIdentifier(Enum): +class ChecksumAlgorithm(Enum): SHA1 = auto() SHA224 = auto() SHA256 = auto() @@ -32,27 +32,47 @@ class ChecksumAlgorithmIdentifier(Enum): MD6 = auto() ADLER32 = auto() - def checksum_to_rdf(self): - return "checksumAlgorithm_" + self.name.lower() + def algorithm_to_rdf_representation(self) -> str: + if self.name.startswith("BLAKE2B"): + return "checksumAlgorithm_" + self.name.replace("_", "").lower() + else: + return "checksumAlgorithm_" + self.name.lower() @classmethod - def checksum_from_rdf(cls, identifier: str) -> str: + def checksum_from_rdf(cls, identifier: str) -> 'ChecksumAlgorithm': identifier = identifier.split('_', 1)[-1].upper() - blake_checksum = re.compile(r"(BLAKE2B)\s*(256|384|512)", re.UNICODE) + blake_checksum = re.compile(r"^(BLAKE2B)(256|384|512)$", re.UNICODE) match = blake_checksum.match(identifier) if match: - return match[1] + '_' + match[2] - return identifier + identifier = match[1] + '_' + match[2] + if identifier not in ChecksumAlgorithm.__members__: + raise ValueError(f"Invalid algorithm for checksum: {identifier}") + return ChecksumAlgorithm[identifier] + + @classmethod + def checksum_algorithm_from_string(cls, identifier: str) -> 'ChecksumAlgorithm': + identifier.replace("-", "_").upper() + if identifier not in ChecksumAlgorithm.__members__: + raise ValueError(f"Invalid algorithm for checksum: {identifier}") + return ChecksumAlgorithm[identifier] -class Algorithm(object): +class Checksum(object): """Generic checksum algorithm.""" - def __init__(self, identifier: str, value): - if identifier.upper().replace('-', '_') not in ChecksumAlgorithmIdentifier.__members__: - raise ValueError('Invalid algorithm for Checksum: {}'.format(identifier)) + def __init__(self, identifier: ChecksumAlgorithm, value: str): self.identifier = identifier self.value = value + @classmethod + def checksum_from_string(cls, value: str) -> 'Checksum': + CHECKSUM_RE = re.compile("(ADLER32|BLAKE2b-256|BLAKE2b-384|BLAKE2b-512|BLAKE3|MD2|MD4|MD5|MD6|" \ + "SHA1|SHA224|SHA256|SHA384|SHA512|SHA3-256|SHA3-384|SHA3-512):\\s*([a-fA-F0-9]*)") + match = CHECKSUM_RE.match(value) + if match is None or match.group(1) is None or match.group(2) is None: + raise ValueError(f"Invalid checksum: {value}") + identifier = ChecksumAlgorithm.checksum_algorithm_from_string(match.group(1)) + return Checksum(identifier=identifier, value=match.group(2)) + def to_tv(self): - return "{0}: {1}".format(self.identifier, self.value) + return "{0}: {1}".format(self.identifier.name, self.value) diff --git a/spdx/cli_tools/parser.py b/spdx/cli_tools/parser.py index 891a3017a..4b5d45a21 100755 --- a/spdx/cli_tools/parser.py +++ b/spdx/cli_tools/parser.py @@ -52,7 +52,7 @@ def main(file, force): ) print("Package Homepage: {0}".format(package.homepage)) for checksum in doc.package.checksums.values(): - print("Package Checksum: {0} {1}".format(checksum.identifier, checksum.value)) + print("Package Checksum: {0} {1}".format(checksum.identifier.name, checksum.value)) print("Package Attribution Text: {0}".format(package.attribution_text)) print("Package verification code: {0}".format(package.verif_code)) print( @@ -82,8 +82,8 @@ def main(file, force): print("\tFile name: {0}".format(f.name)) for file_type in f.file_types: print("\tFile type: {0}".format(file_type.name)) - for file_checksum in f.checksums: - print("\tFile Checksum: {0} {1}".format(file_checksum.identifier, file_checksum.value)) + for file_checksum in f.checksums.values(): + print("\tFile Checksum: {0} {1}".format(file_checksum.identifier.name, file_checksum.value)) print("\tFile license concluded: {0}".format(f.conc_lics)) print( "\tFile license info in file: {0}".format( diff --git a/spdx/document.py b/spdx/document.py index 2e0a65950..c14e891d7 100644 --- a/spdx/document.py +++ b/spdx/document.py @@ -34,25 +34,25 @@ class ExternalDocumentRef(object): """ def __init__( - self, external_document_id=None, spdx_document_uri=None, check_sum=None + self, external_document_id=None, spdx_document_uri=None, checksum=None ): self.external_document_id = external_document_id self.spdx_document_uri = spdx_document_uri - self.check_sum = check_sum + self.checksum = checksum def __eq__(self, other): return ( isinstance(other, ExternalDocumentRef) and self.external_document_id == other.external_document_id and self.spdx_document_uri == other.spdx_document_uri - and self.check_sum == other.check_sum + and self.checksum == other.checksum ) def __lt__(self, other): - return (self.external_document_id, self.spdx_document_uri, self.check_sum) < ( + return (self.external_document_id, self.spdx_document_uri, self.checksum) < ( other.external_document_id, other.spdx_document_uri, - other.check_sum, + other.checksum, ) def validate(self, messages: ErrorMessages) -> ErrorMessages: @@ -74,7 +74,7 @@ def validate_spdx_doc_uri(self, messages): messages.append("ExternalDocumentRef has no SPDX Document URI.") def validate_checksum(self, messages): - if not self.check_sum: + if not self.checksum: messages.append("ExternalDocumentRef has no Checksum.") diff --git a/spdx/file.py b/spdx/file.py index 219c9d6bd..7781b7ea7 100644 --- a/spdx/file.py +++ b/spdx/file.py @@ -14,10 +14,11 @@ from functools import total_ordering import hashlib -from spdx.checksum import Algorithm, ChecksumAlgorithmIdentifier -from spdx import utils from spdx.license import License +from spdx import utils +from spdx.checksum import Checksum, ChecksumAlgorithm from spdx.parsers.builderexceptions import SPDXValueError +from spdx.parsers.loggers import ErrorMessages class FileType(Enum): @@ -59,7 +60,7 @@ class File(object): referenced by other elements. Mandatory, one. Type: str. - comment: File comment str, Optional zero or one. - file_types: list of file types. Cardinality 0..* - - checksums: Dict with identifier of spdx.checksum.Algorithm as key and spdx.checksum.Algorithm as value, + - checksums: Dict with checksum.ChecksumAlgorithm as key and checksum.Checksum as value, there must be a SHA1 hash, at least. - conc_lics: Mandatory one. license.License or utils.NoAssert or utils.SPDXNone. - licenses_in_file: list of licenses found in file, mandatory one or more. @@ -101,22 +102,22 @@ def __lt__(self, other): return self.name < other.name @property - def chk_sum(self): + def checksum(self): """ Backwards compatibility, return SHA1 checksum. """ warnings.warn("This property is deprecated. Use get_checksum instead.") - return self.get_checksum(ChecksumAlgorithmIdentifier.SHA1) + return self.get_checksum(ChecksumAlgorithm.SHA1) - @chk_sum.setter - def chk_sum(self, value): + @checksum.setter + def checksum(self, value): """ Backwards compatibility, set checksum. """ warnings.warn("This property is deprecated. Use set_checksum instead.") if isinstance(value, str): - self.set_checksum(Algorithm("SHA1", value)) - elif isinstance(value, Algorithm): + self.set_checksum(Checksum("SHA1", value)) + elif isinstance(value, Checksum): self.set_checksum(value) def add_lics(self, lics): @@ -144,7 +145,7 @@ def validate(self, messages): messages.push_context(self.name) self.validate_concluded_license(messages) self.validate_file_types(messages) - self.validate_checksum(messages) + self.validate_checksums(messages) self.validate_licenses_in_file(messages) self.validate_copyright(messages) self.validate_artifacts(messages) @@ -211,13 +212,16 @@ def validate_file_types(self, messages): messages.append(f"{file_type} is not of type FileType.") return messages - def validate_checksum(self, messages): - if self.get_checksum(ChecksumAlgorithmIdentifier.SHA1) is None: + def validate_checksums(self, messages: ErrorMessages): + for checksum in self.checksums.values(): + if not isinstance(checksum, Checksum): + messages.append("File checksum must be instance of spdx.checksum.Checksum.") + + if self.get_checksum(ChecksumAlgorithm.SHA1) is None: messages.append("At least one file checksum algorithm must be SHA1") - return messages def calculate_checksum(self, hash_algorithm='SHA1'): - if hash_algorithm not in ChecksumAlgorithmIdentifier.__members__: + if hash_algorithm not in ChecksumAlgorithm.__members__: raise ValueError BUFFER_SIZE = 65536 @@ -231,14 +235,13 @@ def calculate_checksum(self, hash_algorithm='SHA1'): return file_hash.hexdigest() - def get_checksum(self, hash_algorithm: ChecksumAlgorithmIdentifier = ChecksumAlgorithmIdentifier.SHA1) -> Algorithm: - return self.checksums[hash_algorithm.name] + def get_checksum(self, hash_algorithm: ChecksumAlgorithm = ChecksumAlgorithm.SHA1) -> Checksum: + return self.checksums[hash_algorithm] - def set_checksum(self, new_checksum: Algorithm): - if not isinstance(new_checksum, Algorithm): + def set_checksum(self, new_checksum: Checksum): + if not isinstance(new_checksum, Checksum): raise SPDXValueError - if new_checksum.identifier in self.checksums: - return + self.checksums[new_checksum.identifier] = new_checksum def has_optional_field(self, field): diff --git a/spdx/package.py b/spdx/package.py index 3f0095ab9..fdb909c36 100644 --- a/spdx/package.py +++ b/spdx/package.py @@ -17,7 +17,7 @@ from spdx import creationinfo from spdx import license from spdx import utils -from spdx.checksum import Algorithm, ChecksumAlgorithmIdentifier +from spdx.checksum import Checksum, ChecksumAlgorithm from spdx.parsers.builderexceptions import SPDXValueError from spdx.parsers.loggers import ErrorMessages @@ -60,7 +60,7 @@ class Package(object): whenever files_analyzed is True or None (omitted) and Must be None (omitted) if files_analyzed is False. However, as a convenience within this library, we allow this to be Optional even when files_analyzed is True/None. - - checksums: Optional, Dict with identifier of spdx.checksum.Algorithm as key and spdx.checksum.Algorithm as value. + - checksums: Optional, Dict with checksum.ChecksumAlgorithm as key and checksum.Checksum as value. - source_info: Optional string. - conc_lics: Mandatory license.License or utils.SPDXNone or utils.NoAssert. @@ -120,22 +120,22 @@ def __init__( self.valid_until_date: Optional[datetime] = None @property - def check_sum(self): + def checksum(self): """ Backwards compatibility, return SHA1 checksum. """ warnings.warn("This property is deprecated. Use get_checksum instead.") - return self.get_checksum(ChecksumAlgorithmIdentifier.SHA1) + return self.get_checksum(ChecksumAlgorithm.SHA1) - @check_sum.setter - def check_sum(self, value): + @checksum.setter + def checksum(self, value): """ Backwards compatibility, set SHA1 checksum. """ warnings.warn("This property is deprecated. Use set_checksum instead.") if isinstance(value, str): - self.set_checksum(Algorithm("SHA1", value)) - elif isinstance(value, Algorithm): + self.set_checksum(Checksum("SHA1", value)) + elif isinstance(value, Checksum): self.set_checksum(value) @property @@ -160,7 +160,7 @@ def validate(self, messages): """ messages.push_context(self.name) self.validate_files_analyzed(messages) - self.validate_checksum(messages) + self.validate_checksums(messages) self.validate_optional_str_fields(messages) self.validate_mandatory_str_fields(messages) self.validate_pkg_ext_refs(messages) @@ -291,23 +291,20 @@ def validate_str_fields(self, fields, optional, messages): return messages - def validate_checksum(self, messages): + def validate_checksums(self, messages: ErrorMessages): if not self.checksums: - return messages - try: - self.get_checksum(ChecksumAlgorithmIdentifier.SHA1) - except KeyError: - messages.append("At least one package checksum algorithm must be SHA1") - return messages - - def get_checksum(self, hash_algorithm: ChecksumAlgorithmIdentifier = ChecksumAlgorithmIdentifier.SHA1) -> Algorithm: - return self.checksums[hash_algorithm.name] - - def set_checksum(self, new_checksum: Algorithm): - if not isinstance(new_checksum, Algorithm): - raise SPDXValueError("Package::Checksum") - if new_checksum.identifier in self.checksums: return + for checksum in self.checksums.values(): + if not isinstance(checksum, Checksum): + messages.append("Package checksum must be instance of spdx.checksum.Checksum") + + def get_checksum(self, hash_algorithm: ChecksumAlgorithm = ChecksumAlgorithm.SHA1) -> Checksum: + return self.checksums[hash_algorithm] + + def set_checksum(self, new_checksum: Checksum): + if not isinstance(new_checksum, Checksum): + raise SPDXValueError("Package::Checksum") + self.checksums[new_checksum.identifier] = new_checksum def has_optional_field(self, field): diff --git a/spdx/parsers/jsonyamlxml.py b/spdx/parsers/jsonyamlxml.py index 815cba485..0e8916a6f 100644 --- a/spdx/parsers/jsonyamlxml.py +++ b/spdx/parsers/jsonyamlxml.py @@ -10,7 +10,7 @@ # limitations under the License. from datetime import datetime from enum import Enum, auto -from typing import List, Dict, Tuple, Callable +from typing import List, Dict, Tuple, Callable, Optional from spdx import document from spdx import utils @@ -1093,10 +1093,10 @@ def _handle_file_dependency(self, file_dependency): return None return None - def parse_file_checksums(self, file_checksums): + def parse_file_checksums(self, file_checksums: List[Dict]) -> Optional[bool]: """ Parse File checksums - - file_checksum: Python List + - file_checksums: Python List """ if isinstance(file_checksums, list): for checksum in file_checksums: @@ -1593,10 +1593,10 @@ def parse_pkg_files(self, pkg_has_files: List[str], method_to_parse_relationship elif pkg_has_files is not None: self.value_error("PKG_HAS_FILES", pkg_has_files) - def parse_pkg_checksums(self, pkg_checksums): + def parse_pkg_checksums(self, pkg_checksums: List[Dict]) -> Optional[bool]: """ - Parse Package checksum - - pkg_chksum: Python str/unicode + Parse Package checksums + - pkg_chksums: Python List """ if isinstance(pkg_checksums, list): for checksum in pkg_checksums: diff --git a/spdx/parsers/jsonyamlxmlbuilders.py b/spdx/parsers/jsonyamlxmlbuilders.py index 189e7e2e1..d514af7ab 100644 --- a/spdx/parsers/jsonyamlxmlbuilders.py +++ b/spdx/parsers/jsonyamlxmlbuilders.py @@ -8,11 +8,13 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -from spdx import file +from typing import Dict, Union + +from spdx.document import Document from spdx.parsers import rdfbuilders from spdx.parsers import tagvaluebuilders from spdx.parsers import validations -from spdx.checksum import Algorithm +from spdx.checksum import Checksum, ChecksumAlgorithm from spdx.parsers.builderexceptions import SPDXValueError from spdx.parsers.builderexceptions import CardinalityError from spdx.parsers.builderexceptions import OrderError @@ -160,20 +162,24 @@ class FileBuilder(rdfbuilders.FileBuilder): def __init__(self): super(FileBuilder, self).__init__() - def set_file_checksum(self, doc, checksum): + def set_file_checksum(self, doc: Document, checksum: Union[Dict, Checksum, str]) -> bool: """ Set the file checksum. checksum - A string + raise OrderError if no file defined. """ - if self.has_file(doc): - if isinstance(checksum, dict): - algo = checksum.get('algorithm') or 'SHA1' - self.file(doc).set_checksum(Algorithm(algo, checksum.get('checksumValue'))) - elif isinstance(checksum, Algorithm): - self.file(doc).set_checksum(checksum) - else: - self.file(doc).set_checksum(Algorithm("SHA1", checksum)) - return True + if not self.has_file(doc): + raise OrderError("No file for checksum defined.") + + if isinstance(checksum, dict): + algo = checksum.get('algorithm') or 'SHA1' + identifier = ChecksumAlgorithm.checksum_algorithm_from_string(algo) + self.file(doc).set_checksum(Checksum(identifier, checksum.get('checksumValue'))) + elif isinstance(checksum, Checksum): + self.file(doc).set_checksum(checksum) + elif isinstance(checksum, str): + self.file(doc).set_checksum(Checksum(ChecksumAlgorithm.SHA1, checksum)) + return True def set_file_notice(self, doc, text): """ diff --git a/spdx/parsers/lexers/tagvalue.py b/spdx/parsers/lexers/tagvalue.py index ba7aa62a9..83c709a0d 100644 --- a/spdx/parsers/lexers/tagvalue.py +++ b/spdx/parsers/lexers/tagvalue.py @@ -166,7 +166,7 @@ def t_text_error(self, t): def t_CHKSUM(self, t): r":\s*(ADLER32|BLAKE2b-256|BLAKE2b-384|BLAKE2b-512|BLAKE3|MD2|MD4|MD5|MD6|" \ - "SHA1|SHA224|SHA256|SHA384|SHA512|SHA3-256|SHA3-384|SHA3-512):\s*([a-f0-9]*)" + "SHA1|SHA224|SHA256|SHA384|SHA512|SHA3-256|SHA3-384|SHA3-512):\s*([a-fA-F0-9]*)" t.value = t.value[1:].strip() return t diff --git a/spdx/parsers/rdf.py b/spdx/parsers/rdf.py index 389b5ca5f..279156867 100644 --- a/spdx/parsers/rdf.py +++ b/spdx/parsers/rdf.py @@ -21,7 +21,7 @@ from spdx import document from spdx import license from spdx import utils -from spdx.checksum import Algorithm, ChecksumAlgorithmIdentifier +from spdx.checksum import Checksum, ChecksumAlgorithm from spdx.parsers.builderexceptions import CardinalityError from spdx.parsers.builderexceptions import SPDXValueError from spdx.parsers.loggers import ErrorMessages @@ -67,14 +67,12 @@ } -def convert_rdf_checksum_algorithm(algo): - ss = algo.split('#') - if len(ss) != 2: - raise SPDXValueError('Unknown checksum algorithm {}'.format(algo)) - algo = ChecksumAlgorithmIdentifier.checksum_from_rdf(ss[1]) - if algo is None: - raise SPDXValueError('Unknown checksum algorithm {}'.format(algo)) - return algo +def convert_rdf_checksum_algorithm(rdf_checksum_algorithm: str) -> ChecksumAlgorithm: + split_string = rdf_checksum_algorithm.split('#') + if len(split_string) != 2: + raise SPDXValueError('Unknown checksum algorithm {}'.format(rdf_checksum_algorithm)) + checksum_algorithm = ChecksumAlgorithm.checksum_from_rdf(split_string[1]) + return checksum_algorithm class BaseParser(object): @@ -523,7 +521,7 @@ def p_pkg_checksum(self, p_term, predicate): (pkg_checksum, self.spdx_namespace["algorithm"], None) ): algorithm_identifier = convert_rdf_checksum_algorithm(str(algo)) - checksum = Algorithm(algorithm_identifier, str(value)) + checksum = Checksum(algorithm_identifier, str(value)) self.builder.set_pkg_checksum(self.doc, checksum) def p_pkg_homepg(self, p_term, predicate): @@ -793,7 +791,7 @@ def p_file_checksum(self, f_term, predicate): (file_checksum, self.spdx_namespace["algorithm"], None) ): algorithm_identifier = convert_rdf_checksum_algorithm(str(algo)) - checksum = Algorithm(algorithm_identifier, str(value)) + checksum = Checksum(algorithm_identifier, str(value)) self.builder.set_file_checksum(self.doc, checksum) def p_file_lic_conc(self, f_term, predicate): diff --git a/spdx/parsers/rdfbuilders.py b/spdx/parsers/rdfbuilders.py index ef812f4b3..c7845ae4d 100644 --- a/spdx/parsers/rdfbuilders.py +++ b/spdx/parsers/rdfbuilders.py @@ -10,13 +10,14 @@ # limitations under the License. import re -from typing import Dict +from typing import Dict, Union from spdx import file from spdx import license from spdx import package from spdx import version -from spdx.checksum import Algorithm +from spdx.checksum import Checksum, ChecksumAlgorithm +from spdx.document import Document from spdx.parsers.builderexceptions import CardinalityError from spdx.parsers.builderexceptions import OrderError from spdx.parsers.builderexceptions import SPDXValueError @@ -144,8 +145,8 @@ def set_chksum(self, doc, chk_sum): chk_sum - The checksum value in the form of a string. """ if chk_sum: - doc.ext_document_references[-1].check_sum = Algorithm( - "SHA1", chk_sum + doc.ext_document_references[-1].checksum = Checksum( + ChecksumAlgorithm.SHA1, chk_sum ) else: raise SPDXValueError("ExternalDocumentRef::Checksum") @@ -187,21 +188,26 @@ class PackageBuilder(tagvaluebuilders.PackageBuilder): def __init__(self): super(PackageBuilder, self).__init__() - def set_pkg_checksum(self, doc, checksum: [Algorithm, Dict]): + def set_pkg_checksum(self, doc, checksum: Union[Checksum, Dict]): """ Set the package checksum. - checksum - A string + checksum - A Checksum or a Dict Raise SPDXValueError if checksum type invalid. Raise OrderError if no package previously defined. """ self.assert_package_exists() if isinstance(checksum, dict): - algo = checksum.get('algorithm') or 'SHA1' + algo = checksum.get('algorithm') or ChecksumAlgorithm.SHA1 if algo.startswith('checksumAlgorithm_'): - algo = convert_rdf_checksum_algorithm(algo) or 'SHA1' - doc.packages[-1].set_checksum(Algorithm(identifier=algo, value=checksum.get('checksumValue'))) - elif isinstance(checksum, Algorithm): + algo = convert_rdf_checksum_algorithm(algo) or ChecksumAlgorithm.SHA1 + else: + algo = ChecksumAlgorithm.checksum_algorithm_from_string(algo) + doc.packages[-1].set_checksum(Checksum(identifier=algo, value=checksum.get('checksumValue'))) + elif isinstance(checksum, Checksum): doc.packages[-1].set_checksum(checksum) + elif isinstance(checksum, str): + # kept for backwards compatibility + doc.packages[-1].set_checksum(Checksum(identifier=ChecksumAlgorithm.SHA1, value=checksum)) else: raise SPDXValueError("Invalid value for package checksum.") @@ -387,21 +393,21 @@ class FileBuilder(tagvaluebuilders.FileBuilder): def __init__(self): super(FileBuilder, self).__init__() - def set_file_checksum(self, doc, chk_sum): + def set_file_checksum(self, doc: Document, chk_sum: Union[Checksum, Dict, str]): """ Set the file check sum, if not already set. - chk_sum - A string - Raise CardinalityError if already defined. - Raise OrderError if no package previously defined. + chk_sum - A checksum.Checksum or a dict """ - if self.has_package(doc) and self.has_file(doc): + if self.has_file(doc): if isinstance(chk_sum, dict): - self.file(doc).set_checksum(Algorithm(chk_sum.get('algorithm'), - chk_sum.get('checksumValue'))) - elif isinstance(chk_sum, Algorithm): + identifier = ChecksumAlgorithm.checksum_algorithm_from_string(chk_sum.get('algorithm')) + self.file(doc).set_checksum(Checksum(identifier, + chk_sum.get('checksumValue'))) + elif isinstance(chk_sum, Checksum): self.file(doc).set_checksum(chk_sum) - else: - self.file(doc).set_checksum(Algorithm("SHA1", chk_sum)) + elif isinstance(chk_sum, str): + # kept for backwards compatibility + self.file(doc).set_checksum(Checksum(ChecksumAlgorithm.SHA1, chk_sum)) return True def set_file_license_comment(self, doc, text): diff --git a/spdx/parsers/tagvaluebuilders.py b/spdx/parsers/tagvaluebuilders.py index 6564f5e25..5f03816c4 100644 --- a/spdx/parsers/tagvaluebuilders.py +++ b/spdx/parsers/tagvaluebuilders.py @@ -9,12 +9,10 @@ # See the License for the specific language governing permissions and # limitations under the License. -from enum import auto, Enum import re from typing import Dict from spdx import annotation -from spdx import checksum from spdx import creationinfo from spdx import file from spdx import license @@ -24,9 +22,9 @@ from spdx import snippet from spdx import utils from spdx import version -from spdx.checksum import Algorithm +from spdx.checksum import Checksum -from spdx.document import ExternalDocumentRef +from spdx.document import ExternalDocumentRef, Document from spdx.package import PackagePurpose from spdx.parsers.builderexceptions import CardinalityError from spdx.parsers.builderexceptions import OrderError @@ -34,16 +32,6 @@ from spdx.parsers import validations -def checksum_algorithm_from_string(value): - CHECKSUM_RE = re.compile("(ADLER32|BLAKE2b-256|BLAKE2b-384|BLAKE2b-512|BLAKE3|MD2|MD4|MD5|MD6|" \ - "SHA1|SHA224|SHA256|SHA384|SHA512|SHA3-256|SHA3-384|SHA3-512):\\s*([a-f0-9]*)") - match = CHECKSUM_RE.match(value) - if match: - return Algorithm(identifier=match.group(1), value=match.group(2)) - else: - return None - - def str_from_text(text) -> str: """ Return content of a free form text block as a string. @@ -199,7 +187,7 @@ def set_chksum(self, doc, chksum): """ Set the `check_sum` attribute of the `ExternalDocumentRef` object. """ - doc.ext_document_references[-1].check_sum = checksum_algorithm_from_string(chksum) + doc.ext_document_references[-1].checksum = Checksum.checksum_from_string(chksum) def add_ext_doc_refs(self, doc, ext_doc_id, spdx_doc_uri, chksum): self.set_ext_doc_id(doc, ext_doc_id) @@ -785,7 +773,7 @@ def set_pkg_checksum(self, doc, checksum): """ self.assert_package_exists() self.package_chk_sum_set = True - doc.packages[-1].set_checksum(checksum_algorithm_from_string(checksum)) + doc.packages[-1].set_checksum(Checksum.checksum_from_string(checksum)) return True def set_pkg_source_info(self, doc, text): @@ -1190,15 +1178,13 @@ def set_file_type(self, doc, type_value): spdx_file.file_types.append(file_type) - def set_file_checksum(self, doc, checksum): + def set_file_checksum(self, doc: Document, checksum: str): """ Raise OrderError if no file defined. - Raise CardinalityError if no SHA1 checksum set. """ if self.has_file(doc): - new_checksum = checksum_algorithm_from_string(checksum) + new_checksum = Checksum.checksum_from_string(checksum) self.file(doc).set_checksum(new_checksum) - self.file_chksum_set = True else: raise OrderError("File::CheckSum") return True diff --git a/spdx/utils.py b/spdx/utils.py index 03b526df6..3695cd0bd 100644 --- a/spdx/utils.py +++ b/spdx/utils.py @@ -17,7 +17,8 @@ from ply import lex from ply import yacc -from spdx import checksum +from spdx.checksum import ChecksumAlgorithm + if TYPE_CHECKING: from spdx.file import File from spdx.package import Package @@ -212,18 +213,18 @@ def parse(self, data): def calc_verif_code(files: List['File']) -> str: list_of_file_hashes = [] - hash_algo_name = "SHA1" - for f in files: - file_chksum = f.get_checksum(hash_algo_name) - if file_chksum is not None: - file_ch = file_chksum.value + hash_algorithm_name = ChecksumAlgorithm.SHA1 + for file in files: + file_checksum = file.get_checksum(hash_algorithm_name) + if file_checksum is not None: + file_checksum_value = file_checksum.value else: - file_ch = f.calculate_checksum(hash_algo_name) - list_of_file_hashes.append(file_ch) + file_checksum_value = file.calculate_checksum(hash_algorithm_name) + list_of_file_hashes.append(file_checksum_value) list_of_file_hashes.sort() - hasher = hashlib.new(hash_algo_name.lower()) + hasher = hashlib.new(hash_algorithm_name.name.lower()) hasher.update("".join(list_of_file_hashes).encode("utf-8")) return hasher.hexdigest() diff --git a/spdx/writers/json.py b/spdx/writers/json.py index 732b6900f..a2b226fdf 100644 --- a/spdx/writers/json.py +++ b/spdx/writers/json.py @@ -30,7 +30,6 @@ def write_document(document, out, validate=True): messages = ErrorMessages() messages = document.validate(messages) if messages: - print(messages.messages) raise InvalidDocumentError(messages) writer = Writer(document) diff --git a/spdx/writers/jsonyamlxml.py b/spdx/writers/jsonyamlxml.py index b77224716..3f0f8bac8 100644 --- a/spdx/writers/jsonyamlxml.py +++ b/spdx/writers/jsonyamlxml.py @@ -13,6 +13,7 @@ from rdflib import Literal from spdx import license, utils +from spdx.checksum import Checksum from spdx.package import ExternalPackageRef from spdx.relationship import Relationship from spdx.utils import update_dict_item_with_new_item @@ -45,14 +46,11 @@ def license(self, license_field): license_str = license_field.__str__() return license_str - def checksum_to_dict(self, checksum_field): + def checksum_to_dict(self, checksum_field: Checksum) -> Dict: """ - Return a dictionary representation of a spdx.checksum.Algorithm object + Return a dictionary representation of a checksum.Checksum object """ - #checksum_object = {'algorithm': "checksumAlgorithm_" + checksum_field.identifier.lower(), - # 'checksumValue': checksum_field.value} - #return checksum_object - return {'algorithm': checksum_field.identifier, 'checksumValue': checksum_field.value} + return {'algorithm': checksum_field.identifier.name, 'checksumValue': checksum_field.value} def spdx_id(self, spdx_id_field): return spdx_id_field.__str__().split("#")[-1] @@ -521,7 +519,7 @@ def create_ext_document_references(self): ] = ext_document_reference.spdx_document_uri ext_document_reference_object["checksum"] = self.checksum_to_dict( - ext_document_reference.check_sum + ext_document_reference.checksum ) ext_document_reference_objects.append(ext_document_reference_object) diff --git a/spdx/writers/rdf.py b/spdx/writers/rdf.py index 23936f969..193c46658 100644 --- a/spdx/writers/rdf.py +++ b/spdx/writers/rdf.py @@ -22,7 +22,7 @@ from spdx import file from spdx import license from spdx import utils -from spdx.checksum import ChecksumAlgorithmIdentifier +from spdx.checksum import Checksum from spdx.package import Package from spdx.parsers.loggers import ErrorMessages from spdx.relationship import Relationship @@ -45,11 +45,11 @@ def __init__(self, document, out): self.spdx_namespace = Namespace("http://spdx.org/rdf/terms#") self.graph = Graph() - def create_checksum_node(self, checksum): + def create_checksum_node(self, checksum: Checksum) -> BNode: """ Return a node representing spdx.checksum. """ - algo = ChecksumAlgorithmIdentifier[checksum.identifier].checksum_to_rdf() or 'checksumAlgorithm_sha1' + algo = checksum.identifier.algorithm_to_rdf_representation() or 'checksumAlgorithm_sha1' checksum_node = BNode() type_triple = (checksum_node, RDF.type, self.spdx_namespace.Checksum) self.graph.add(type_triple) @@ -668,7 +668,7 @@ def create_external_document_ref_node(self, ext_document_references): doc_uri_triple = (ext_doc_ref_node, self.spdx_namespace.spdxDocument, doc_uri) self.graph.add(doc_uri_triple) - checksum_node = self.create_checksum_node(ext_document_references.check_sum) + checksum_node = self.create_checksum_node(ext_document_references.checksum) self.graph.add((ext_doc_ref_node, self.spdx_namespace.checksum, checksum_node)) return ext_doc_ref_node diff --git a/spdx/writers/tagvalue.py b/spdx/writers/tagvalue.py index c717206e8..f3abbbd39 100644 --- a/spdx/writers/tagvalue.py +++ b/spdx/writers/tagvalue.py @@ -357,7 +357,7 @@ def write_document(document, out, validate=True): [ doc_ref.external_document_id, doc_ref.spdx_document_uri, - doc_ref.check_sum.identifier + ":" + doc_ref.check_sum.value, + doc_ref.checksum.identifier.name + ": " + doc_ref.checksum.value, ] ) write_value("ExternalDocumentRef", doc_ref_str, out) diff --git a/tests/data/doc_parse/spdx-expected.json b/tests/data/doc_parse/spdx-expected.json index ee30bd895..fce55cb2c 100644 --- a/tests/data/doc_parse/spdx-expected.json +++ b/tests/data/doc_parse/spdx-expected.json @@ -48,13 +48,16 @@ "copyrightText": "(c) Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Hewlett-Packard Development Company, LP", "licenseComment": "This license is used by Jena", "notice": null, - "checksums": [{ - "identifier": "SHA1", - "value": "3ab4e1c67a2d28fced849ee1bb76e7391b93f125" - },{ - "identifier": "SHA256", - "value": "3ab4e1c67a2d28fced849ee1bb76e7391b93f1250000000000000000" - }], + "checksums": [ + { + "identifier": "SHA1", + "value": "3ab4e1c67a2d28fced849ee1bb76e7391b93f125" + }, + { + "identifier": "SHA256", + "value": "3ab4e1c67a2d28fced849ee1bb76e7391b93f1250000000000000000" + } + ], "licenseInfoInFiles": [ { "type": "Single", @@ -93,7 +96,8 @@ { "identifier": "SHA256", "value": "2fd4e1c67a2d28fced849ee1bb76e7391b93eb120000000000000000" - }], + } + ], "licenseInfoInFiles": [ { "type": "Single", @@ -171,10 +175,12 @@ }, "copyrightText": " Copyright 2010, 2011 Source Auditor Inc.", "licenseComment": "The declared license information can be found in the NOTICE file at the root of the archive file", - "checksums": [{ - "identifier": "SHA1", - "value": "2fd4e1c67a2d28fced849ee1bb76e7391b93eb12" - }], + "checksums": [ + { + "identifier": "SHA1", + "value": "2fd4e1c67a2d28fced849ee1bb76e7391b93eb12" + } + ], "licenseInfoFromFiles": [ { "type": "Single", diff --git a/tests/data/doc_write/json-simple-plus.json b/tests/data/doc_write/json-simple-plus.json index fae11a34d..e9be761eb 100644 --- a/tests/data/doc_write/json-simple-plus.json +++ b/tests/data/doc_write/json-simple-plus.json @@ -14,11 +14,12 @@ "documentDescribes": [ "SPDXRef-Package" ], - "packages": [ { - "SPDXID": "SPDXRef-Package", - "name": "some/path", - "downloadLocation": "NOASSERTION", - "copyrightText": "Some copyright", + "packages": [ + { + "SPDXID": "SPDXRef-Package", + "name": "some/path", + "downloadLocation": "NOASSERTION", + "copyrightText": "Some copyright", "packageVerificationCode": { "packageVerificationCodeValue": "SOME code" }, @@ -27,12 +28,12 @@ "algorithm": "SHA1", "checksumValue": "SOME-SHA1" }, - { - "algorithm": "SHA256", - "checksumValue": "SOME-SHA256" - } - ], - "licenseDeclared": "NOASSERTION", + { + "algorithm": "SHA256", + "checksumValue": "SOME-SHA256" + } + ], + "licenseDeclared": "NOASSERTION", "licenseConcluded": "NOASSERTION", "licenseInfoFromFiles": [ "LGPL-2.1-or-later" @@ -40,25 +41,25 @@ "hasFiles": [ "SPDXRef-File" ], - "primaryPackagePurpose" : "FILE", - "releaseDate" : "2021-01-01T12:00:00Z", - "builtDate" : "2021-01-01T12:00:00Z", - "validUntilDate" : "2022-01-01T12:00:00Z" + "primaryPackagePurpose": "FILE", + "releaseDate": "2021-01-01T12:00:00Z", + "builtDate": "2021-01-01T12:00:00Z", + "validUntilDate": "2022-01-01T12:00:00Z" } ], "files": [ { "SPDXID": "SPDXRef-File", - "checksums": [ - { - "algorithm": "SHA1", - "checksumValue": "SOME-SHA1" - }, - { - "algorithm": "SHA256", - "checksumValue": "SOME-SHA256" - } - ], + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "SOME-SHA1" + }, + { + "algorithm": "SHA256", + "checksumValue": "SOME-SHA256" + } + ], "licenseConcluded": "NOASSERTION", "copyrightText": "NOASSERTION", "fileName": "./some/path/tofile", diff --git a/tests/data/doc_write/json-simple.json b/tests/data/doc_write/json-simple.json index b2a5fa461..30c1b8943 100644 --- a/tests/data/doc_write/json-simple.json +++ b/tests/data/doc_write/json-simple.json @@ -28,12 +28,12 @@ "algorithm": "SHA1", "checksumValue": "SOME-SHA1" }, - { - "algorithm": "SHA256", - "checksumValue": "SOME-SHA256" - } - ], - "licenseDeclared": "NOASSERTION", + { + "algorithm": "SHA256", + "checksumValue": "SOME-SHA256" + } + ], + "licenseDeclared": "NOASSERTION", "licenseConcluded": "NOASSERTION", "licenseInfoFromFiles": [ "LGPL-2.1-only" @@ -41,10 +41,10 @@ "hasFiles": [ "SPDXRef-File" ], - "primaryPackagePurpose" : "FILE", - "releaseDate" : "2021-01-01T12:00:00Z", - "builtDate" : "2021-01-01T12:00:00Z", - "validUntilDate" : "2022-01-01T12:00:00Z" + "primaryPackagePurpose": "FILE", + "releaseDate": "2021-01-01T12:00:00Z", + "builtDate": "2021-01-01T12:00:00Z", + "validUntilDate": "2022-01-01T12:00:00Z" } ], "files": [ diff --git a/tests/data/formats/SPDXTagExample.tag b/tests/data/formats/SPDXTagExample.tag index 8d9c52847..855ba417a 100644 --- a/tests/data/formats/SPDXTagExample.tag +++ b/tests/data/formats/SPDXTagExample.tag @@ -73,9 +73,8 @@ FileName: src/org/spdx/parser/DOAPProject.java SPDXID: SPDXRef-File1 FileType: SOURCE FileType: TEXT -FileChecksum: SHA1: 2fd4e1c67a2d28fced849ee1bb76e7391b93eb12 +FileChecksum: SHA1: 2fd4e1c67a2d28fced849ee1bb76e7391b93eB12 FileChecksum: SHA256: 2fd4e1c67a2d28fced849ee1bb76e7391b93eb120000000000000000 -FileType: SOURCE LicenseConcluded: Apache-2.0 LicenseInfoInFile: Apache-2.0 FileCopyrightText: Copyright 2010, 2011 Source Auditor Inc. @@ -86,7 +85,6 @@ FileType: ARCHIVE FileType: OTHER FileChecksum: SHA1: 3ab4e1c67a2d28fced849ee1bb76e7391b93f125 FileChecksum: SHA256: 3ab4e1c67a2d28fced849ee1bb76e7391b93f1250000000000000000 -FileType: ARCHIVE LicenseConcluded: LicenseRef-1 LicenseInfoInFile: LicenseRef-1 LicenseComments: This license is used by Jena diff --git a/tests/test_builder.py b/tests/test_builder.py index bac2aedda..810d431e0 100644 --- a/tests/test_builder.py +++ b/tests/test_builder.py @@ -131,7 +131,7 @@ def test_checksum(self): chksum_val = "d6a770ba38583ed4bb4525bd96e50461655d2759" self.builder.set_ext_doc_id(self.document, "DocumentRef-spdx-tool-2.1") self.builder.set_chksum(self.document, chksum) - assert self.document.ext_document_references[-1].check_sum.value == chksum_val + assert self.document.ext_document_references[-1].checksum.value == chksum_val def test_add_ext_doc_refs(self): ext_doc_id_val = "DocumentRef-spdx-tool-2.1" @@ -149,7 +149,7 @@ def test_add_ext_doc_refs(self): assert ( self.document.ext_document_references[-1].spdx_document_uri == spdx_doc_uri ) - assert self.document.ext_document_references[-1].check_sum.value == chksum_val + assert self.document.ext_document_references[-1].checksum.value == chksum_val class TestEntityBuilder(TestCase): diff --git a/tests/test_checksum.py b/tests/test_checksum.py new file mode 100644 index 000000000..ebaaaba2a --- /dev/null +++ b/tests/test_checksum.py @@ -0,0 +1,48 @@ +# Copyright (c) 2022 spdx contributors +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# http://www.apache.org/licenses/LICENSE-2.0 +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import pytest + +from spdx.checksum import ChecksumAlgorithm + + +@pytest.mark.parametrize("algorithm,expected", + [("SHA1", "checksumAlgorithm_sha1"), ("SHA224", "checksumAlgorithm_sha224"), + ("SHA3_256", "checksumAlgorithm_sha3_256"), ("BLAKE2B_256", "checksumAlgorithm_blake2b256"), + ("MD5", "checksumAlgorithm_md5")]) +def test_checksum_to_rdf(algorithm, expected): + test_algorithm = ChecksumAlgorithm[algorithm] + rdf_algorithm = test_algorithm.algorithm_to_rdf_representation() + + assert rdf_algorithm == expected + + +@pytest.mark.parametrize("expected,rdf_algorithm", + [(ChecksumAlgorithm.SHA1, "checksumAlgorithm_sha1"), + (ChecksumAlgorithm.SHA224, "checksumAlgorithm_sha224"), + (ChecksumAlgorithm.SHA3_256, "checksumAlgorithm_sha3_256"), + (ChecksumAlgorithm.BLAKE2B_256, "checksumAlgorithm_blake2b256"), + (ChecksumAlgorithm.MD5, "checksumAlgorithm_md5")]) +def test_checksum_from_rdf(rdf_algorithm, expected): + algorithm = ChecksumAlgorithm.checksum_from_rdf(rdf_algorithm) + + assert algorithm == expected + + +@pytest.mark.parametrize("rdf_algorithm", + ["_checksumAlgorithm_sha1", "checksumAlgorithm_sha_224", "checksumAlgorithm_sha3256", + "checksumAlgorithm_blake2b 256", "checksumAlgorithm_blake2b-256", + "checksumAlgorithm_bblake2b 256"]) +def test_checksum_from_wrong_rdf(rdf_algorithm): + with pytest.raises(ValueError) as error: + ChecksumAlgorithm.checksum_from_rdf(rdf_algorithm) + + assert str(error.value).startswith("Invalid algorithm for checksum") + diff --git a/tests/test_document.py b/tests/test_document.py index f1c1ea89c..7f9a1d677 100644 --- a/tests/test_document.py +++ b/tests/test_document.py @@ -16,7 +16,7 @@ from datetime import datetime from unittest import TestCase -from spdx.checksum import Algorithm +from spdx.checksum import Checksum, ChecksumAlgorithm from spdx.config import LICENSE_MAP, EXCEPTION_MAP from spdx.creationinfo import Tool from spdx.document import Document, ExternalDocumentRef @@ -65,26 +65,26 @@ def test_creation(self): document.add_ext_document_reference( ExternalDocumentRef('DocumentRef-spdx-tool-2.1', 'https://spdx.org/spdxdocs/spdx-tools-v2.1-3F2504E0-4F89-41D3-9A0C-0305E82C3301', - Algorithm('SHA1', 'SOME-SHA1')) + Checksum(ChecksumAlgorithm.SHA1, 'SOME-SHA1')) ) assert document.comment is None assert document.version == Version(2, 1) assert document.data_license.identifier == 'AFL-1.1' assert document.ext_document_references[-1].external_document_id == 'DocumentRef-spdx-tool-2.1' assert document.ext_document_references[-1].spdx_document_uri == 'https://spdx.org/spdxdocs/spdx-tools-v2.1-3F2504E0-4F89-41D3-9A0C-0305E82C3301' - assert document.ext_document_references[-1].check_sum.identifier == 'SHA1' - assert document.ext_document_references[-1].check_sum.value == 'SOME-SHA1' + assert document.ext_document_references[-1].checksum.identifier.name == 'SHA1' + assert document.ext_document_references[-1].checksum.value == 'SOME-SHA1' def test_document_validate_failures_returns_informative_messages(self): doc = Document(Version(2, 1), License.from_identifier('CC0-1.0'), 'Sample_Document-V2.1', spdx_id='SPDXRef-DOCUMENT', namespace='https://spdx.org/spdxdocs/spdx-example-444504E0-4F89-41D3-9A0C-0305E82C3301') pack = doc.package = Package('some/path', NoAssert()) - pack.check_sum = Algorithm('SHA256', 'SOME-SHA256') + pack.set_checksum(Checksum(ChecksumAlgorithm.SHA256, 'SOME-SHA256')) file1 = File('./some/path/tofile') file1.name = './some/path/tofile' file1.spdx_id = 'SPDXRef-File' - file1.chksum = Algorithm('SHA1', 'SOME-SHA1') + file1.set_checksum(Checksum(ChecksumAlgorithm.SHA1, 'SOME-SHA1')) lic1 = License.from_identifier('LGPL-2.1-only') file1.add_lics(lic1) pack.add_lics_from_file(lic1) @@ -92,7 +92,6 @@ def test_document_validate_failures_returns_informative_messages(self): messages = doc.validate(messages) expected = ['Sample_Document-V2.1: Creation info missing created date.', 'Sample_Document-V2.1: No creators defined, must have at least one.', - 'Sample_Document-V2.1: some/path: At least one package checksum algorithm must be SHA1', 'Sample_Document-V2.1: some/path: Package download_location can not be None.'] assert sorted(expected) == sorted(messages) @@ -106,7 +105,7 @@ def test_document_is_valid_when_using_or_later_licenses(self): package = doc.package = Package(name='some/path', download_location=NoAssert()) package.spdx_id = 'SPDXRef-Package' package.cr_text = 'Some copyright' - package.set_checksum(Algorithm('SHA1', 'SOME-SHA1')) + package.set_checksum(Checksum(ChecksumAlgorithm.SHA1, 'SOME-SHA1')) package.verif_code = 'SOME code' package.license_declared = NoAssert() package.conc_lics = NoAssert() @@ -115,7 +114,7 @@ def test_document_is_valid_when_using_or_later_licenses(self): file1.name = './some/path/tofile' file1.spdx_id = 'SPDXRef-File' file1.file_types = [FileType.OTHER] - file1.set_checksum(Algorithm('SHA1', 'SOME-SHA1')) + file1.set_checksum(Checksum(ChecksumAlgorithm.SHA1, 'SOME-SHA1')) file1.conc_lics = NoAssert() file1.copyright = NoAssert() @@ -179,8 +178,8 @@ def _get_lgpl_doc(self, or_later=False): package.spdx_id = 'SPDXRef-Package' package.cr_text = 'Some copyright' package.verif_code = 'SOME code' - package.set_checksum(Algorithm('SHA1', 'SOME-SHA1')) - package.set_checksum(Algorithm('SHA256', 'SOME-SHA256')) + package.set_checksum(Checksum(ChecksumAlgorithm.SHA1, 'SOME-SHA1')) + package.set_checksum(Checksum(ChecksumAlgorithm.SHA256, 'SOME-SHA256')) package.license_declared = NoAssert() package.conc_lics = NoAssert() package.primary_package_purpose = PackagePurpose.FILE @@ -192,8 +191,8 @@ def _get_lgpl_doc(self, or_later=False): file1 = File('./some/path/tofile') file1.name = './some/path/tofile' file1.spdx_id = 'SPDXRef-File' - file1.set_checksum(Algorithm('SHA1', 'SOME-SHA1')) - file1.set_checksum(Algorithm('SHA256', 'SOME-SHA256')) + file1.set_checksum(Checksum(ChecksumAlgorithm.SHA1, 'SOME-SHA1')) + file1.set_checksum(Checksum(ChecksumAlgorithm.SHA256, 'SOME-SHA256')) file1.conc_lics = NoAssert() file1.copyright = NoAssert() file1.file_types = [FileType.OTHER, FileType.SOURCE] @@ -247,7 +246,7 @@ def _get_lgpl_multi_package_doc(self, or_later=False): file1 = File('./some/path/tofile') file1.name = './some/path/tofile' file1.spdx_id = 'SPDXRef-File' - file1.set_checksum(Algorithm('SHA1', 'SOME-SHA1')) + file1.set_checksum(Checksum(ChecksumAlgorithm.SHA1, 'SOME-SHA1')) file1.conc_lics = NoAssert() file1.copyright = NoAssert() diff --git a/tests/test_jsonyamlxml_writer.py b/tests/test_jsonyamlxml_writer.py index ff1ebbbbf..0ed226e36 100644 --- a/tests/test_jsonyamlxml_writer.py +++ b/tests/test_jsonyamlxml_writer.py @@ -5,7 +5,7 @@ import pytest -from spdx.checksum import Algorithm +from spdx.checksum import Checksum, ChecksumAlgorithm from spdx.document import Document from spdx.file import File from spdx.license import License @@ -148,7 +148,7 @@ def minimal_document(): def minimal_file(): file = File(name="Example File", spdx_id="SPDXRef-File") - file.set_checksum(Algorithm('SHA1', 'some-sha1-value')) + file.set_checksum(Checksum(ChecksumAlgorithm.SHA1, 'some-sha1-value')) return file diff --git a/tests/test_package.py b/tests/test_package.py index 944f2516d..3b8325b02 100644 --- a/tests/test_package.py +++ b/tests/test_package.py @@ -12,7 +12,7 @@ import unittest from unittest import TestCase -from spdx.checksum import Algorithm +from spdx.checksum import Checksum from spdx.package import Package @@ -25,11 +25,11 @@ def test_calc_verif_code(self): def test_package_with_non_sha1_check_sum(self): package = Package() - package.set_checksum(Algorithm("SHA256", '')) + package.set_checksum(Checksum("SHA256", '')) # Make sure that validation still works despite the checksum not being SHA1 messages = [] - messages = package.validate_checksum(messages) + package.validate_checksums(messages) if __name__ == '__main__': diff --git a/tests/utils_test.py b/tests/utils_test.py index ae3362f22..c196168f1 100644 --- a/tests/utils_test.py +++ b/tests/utils_test.py @@ -331,7 +331,7 @@ def checksum_to_dict(cls, checksum): if checksum is None: return None return OrderedDict([ - ('identifier', checksum.identifier), + ('identifier', checksum.identifier.name), ('value', checksum.value)]) @classmethod @@ -392,8 +392,8 @@ def files_to_list(cls, files): lics_in_files = sorted(file.licenses_in_file, key=lambda lic: lic.identifier) contributors = sorted(file.contributors, key=lambda c: c.name) chk_sums = [] - for _, chk_sum in file.checksums.items(): - chk_sums.append(cls.checksum_to_dict(chk_sum)) + for checksum in file.checksums.values(): + chk_sums.append(cls.checksum_to_dict(checksum)) file_dict = OrderedDict([ ('id', file.spdx_id), @@ -427,7 +427,7 @@ def ext_document_references_to_list(cls, ext_doc_refs): ext_doc_ref_dict = OrderedDict([ ('externalDocumentId', ext_doc_ref.external_document_id), ('spdxDocument', ext_doc_ref.spdx_document_uri), - ('checksum', cls.checksum_to_dict(ext_doc_ref.check_sum)), + ('checksum', cls.checksum_to_dict(ext_doc_ref.checksum)), ]) ext_doc_refs_list.append(ext_doc_ref_dict)