Skip to content

Commit cba5db5

Browse files
authored
Merge pull request #723 from armintaenzertng/addVerificationCodeCalculator
[issue-722] add `calculate_package_verification_code()`
2 parents 17602fc + f9efcac commit cba5db5

File tree

2 files changed

+116
-1
lines changed

2 files changed

+116
-1
lines changed

src/spdx_tools/spdx/spdx_element_utils.py

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
# SPDX-FileCopyrightText: 2022 spdx contributors
22
#
33
# SPDX-License-Identifier: Apache-2.0
4+
import hashlib
5+
46
from beartype.typing import List, Union
57

6-
from spdx_tools.spdx.model import ExternalDocumentRef, File, Package, Snippet
8+
from spdx_tools.spdx.model import ChecksumAlgorithm, ExternalDocumentRef, File, Package, Snippet
79

810

911
def get_full_element_spdx_id(
@@ -29,3 +31,40 @@ def get_full_element_spdx_id(
2931
raise ValueError(f"external id {external_id} not found in external document references")
3032

3133
return external_uri + "#" + local_id
34+
35+
36+
def calculate_package_verification_code(files: List[File]) -> str:
37+
list_of_file_hashes = []
38+
for file in files:
39+
file_checksum_value = None
40+
for checksum in file.checksums:
41+
if checksum.algorithm == ChecksumAlgorithm.SHA1:
42+
file_checksum_value = checksum.value
43+
if not file_checksum_value:
44+
try:
45+
file_checksum_value = calculate_file_checksum(file.name, ChecksumAlgorithm.SHA1)
46+
except FileNotFoundError:
47+
raise FileNotFoundError(
48+
f"Cannot calculate package verification code because the file '{file.name}' "
49+
f"provides no SHA1 checksum and can't be found at the specified location."
50+
)
51+
list_of_file_hashes.append(file_checksum_value)
52+
53+
list_of_file_hashes.sort()
54+
hasher = hashlib.new("sha1")
55+
hasher.update("".join(list_of_file_hashes).encode("utf-8"))
56+
return hasher.hexdigest()
57+
58+
59+
def calculate_file_checksum(file_name: str, hash_algorithm=ChecksumAlgorithm.SHA1) -> str:
60+
BUFFER_SIZE = 65536
61+
62+
file_hash = hashlib.new(hash_algorithm.name.lower())
63+
with open(file_name, "rb") as file_handle:
64+
while True:
65+
data = file_handle.read(BUFFER_SIZE)
66+
if not data:
67+
break
68+
file_hash.update(data)
69+
70+
return file_hash.hexdigest()
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
# SPDX-FileCopyrightText: 2023 spdx contributors
2+
#
3+
# SPDX-License-Identifier: Apache-2.0
4+
import pytest
5+
6+
from spdx_tools.spdx.model import Checksum, ChecksumAlgorithm, File
7+
from spdx_tools.spdx.spdx_element_utils import calculate_file_checksum, calculate_package_verification_code
8+
9+
10+
@pytest.fixture
11+
def generate_test_files(tmp_path):
12+
file_path_1 = tmp_path.joinpath("file1")
13+
file_path_2 = tmp_path.joinpath("file2")
14+
15+
with open(file_path_1, "wb") as file:
16+
file.write(bytes(111))
17+
with open(file_path_2, "wb") as file:
18+
file.write(bytes(222))
19+
20+
yield str(file_path_1), str(file_path_2)
21+
22+
23+
def test_file_checksum_calculation(generate_test_files):
24+
filepath1, filepath2 = generate_test_files
25+
checksum = calculate_file_checksum(filepath1, ChecksumAlgorithm.SHA1)
26+
assert checksum == "dd90903d2f566a3922979dd5e18378a075c7ed33"
27+
checksum = calculate_file_checksum(filepath2, ChecksumAlgorithm.SHA1)
28+
assert checksum == "140dc52658e2eeee3fdc4d471cce84fec7253fe3"
29+
30+
31+
def test_verification_code_calculation_with_predefined_checksums(generate_test_files):
32+
filepath1, filepath2 = generate_test_files
33+
file1 = File(
34+
filepath1,
35+
"SPDXRef-hello",
36+
[Checksum(ChecksumAlgorithm.SHA1, "20862a6d08391d07d09344029533ec644fac6b21")],
37+
)
38+
file2 = File(
39+
filepath2,
40+
"SPDXRef-Makefile",
41+
[Checksum(ChecksumAlgorithm.SHA1, "69a2e85696fff1865c3f0686d6c3824b59915c80")],
42+
)
43+
verification_code = calculate_package_verification_code([file1, file2])
44+
45+
assert verification_code == "c6cb0949d7cd7439fce8690262a0946374824639"
46+
47+
48+
def test_verification_code_calculation_with_calculated_checksums(generate_test_files):
49+
filepath1, filepath2 = generate_test_files
50+
file1 = File(
51+
filepath1,
52+
"SPDXRef-hello",
53+
[Checksum(ChecksumAlgorithm.MD4, "20862a6d08391d07d09344029533ec644fac6b21")],
54+
)
55+
file2 = File(
56+
filepath2,
57+
"SPDXRef-Makefile",
58+
[Checksum(ChecksumAlgorithm.MD4, "69a2e85696fff1865c3f0686d6c3824b59915c80")],
59+
)
60+
verification_code = calculate_package_verification_code([file1, file2])
61+
62+
assert verification_code == "6f29d813abb63ee52a47dbcb691ea2e70f956328"
63+
64+
65+
def test_verification_code_calculation_with_wrong_file_location():
66+
unknown_file_name = "./unknown_file_name"
67+
file1 = File(
68+
unknown_file_name,
69+
"SPDXRef-unknown",
70+
[Checksum(ChecksumAlgorithm.MD4, "20862a6d08391d07d09344029533ec644fac6b21")],
71+
)
72+
73+
with pytest.raises(FileNotFoundError) as err:
74+
calculate_package_verification_code([file1])
75+
76+
assert unknown_file_name in str(err.value)

0 commit comments

Comments
 (0)