Skip to content

Commit ba5d586

Browse files
committed
Cope with invalid hash algorithms in RECORD
- raise an InvalidRecordEntry - catch such things during wheel validation and include them in the issues reported
1 parent f89b5d9 commit ba5d586

File tree

3 files changed

+36
-5
lines changed

3 files changed

+36
-5
lines changed

src/installer/records.py

+5-3
Original file line numberDiff line numberDiff line change
@@ -175,13 +175,15 @@ def from_elements(cls, path: str, hash_: str, size: str) -> "RecordEntry":
175175
if not path:
176176
issues.append("`path` cannot be empty")
177177

178+
hash_value: Optional[Hash] = None
178179
if hash_:
179180
try:
180-
hash_value: Optional[Hash] = Hash.parse(hash_)
181+
hash_value = Hash.parse(hash_)
182+
if hash_value.name not in hashlib.algorithms_available:
183+
issues.append(f"invalid hash algorithm '{hash_value.name}'")
184+
hash_value = None
181185
except ValueError:
182186
issues.append("`hash` does not follow the required format")
183-
else:
184-
hash_value = None
185187

186188
if size:
187189
try:

src/installer/sources.py

+10-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from typing import BinaryIO, ClassVar, Iterator, List, Optional, Tuple, Type, cast
99

1010
from installer.exceptions import InstallerError
11-
from installer.records import RecordEntry, parse_record_file
11+
from installer.records import InvalidRecordEntry, RecordEntry, parse_record_file
1212
from installer.utils import canonicalize_name, parse_wheel_filename
1313

1414
WheelContentElement = Tuple[Tuple[str, str, str], BinaryIO, bool]
@@ -271,7 +271,15 @@ def validate_record(self, *, validate_contents: bool = True) -> None:
271271
)
272272
continue
273273

274-
record = RecordEntry.from_elements(*record_args)
274+
try:
275+
record = RecordEntry.from_elements(*record_args)
276+
except InvalidRecordEntry as e:
277+
for issue in e.issues:
278+
issues.append(
279+
f"In {self._zipfile.filename}, entry in RECORD file for "
280+
f"{item.filename} is invalid: {issue}"
281+
)
282+
continue
275283

276284
if item.filename == f"{self.dist_info_dir}/RECORD":
277285
# Assert that RECORD doesn't have size and hash.

tests/test_sources.py

+21
Original file line numberDiff line numberDiff line change
@@ -325,3 +325,24 @@ def test_rejects_record_validation_failed(self, fancy_wheel):
325325
match="hash / size of (.+) didn't match RECORD",
326326
):
327327
source.validate_record()
328+
329+
def test_rejects_record_containing_unknown_hash(self, fancy_wheel):
330+
with WheelFile.open(fancy_wheel) as source:
331+
record_file_contents = source.read_dist_info("RECORD")
332+
333+
new_record_file_contents = record_file_contents.replace("sha256=", "sha=")
334+
replace_file_in_zip(
335+
fancy_wheel,
336+
filename="fancy-1.0.0.dist-info/RECORD",
337+
content=new_record_file_contents,
338+
)
339+
340+
with WheelFile.open(fancy_wheel) as source:
341+
with pytest.raises(
342+
WheelFile.validation_error,
343+
match=(
344+
"In .+, entry in RECORD file for .+ is invalid: "
345+
"invalid hash algorithm 'sha'"
346+
),
347+
):
348+
source.validate_record(validate_contents=True)

0 commit comments

Comments
 (0)