Skip to content

Commit ee5d243

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 b53c5d1 commit ee5d243

File tree

3 files changed

+38
-5
lines changed

3 files changed

+38
-5
lines changed

src/installer/records.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -192,13 +192,15 @@ def from_elements(cls, path: str, hash_: str, size: str) -> "RecordEntry":
192192
if not path:
193193
issues.append("`path` cannot be empty")
194194

195+
hash_value: Optional[Hash] = None
195196
if hash_:
196197
try:
197-
hash_value: Optional[Hash] = Hash.parse(hash_)
198+
hash_value = Hash.parse(hash_)
199+
if hash_value.name not in hashlib.algorithms_available:
200+
issues.append(f"invalid hash algorithm '{hash_value.name}'")
201+
hash_value = None
198202
except ValueError:
199203
issues.append("`hash` does not follow the required format")
200-
else:
201-
hash_value = None
202204

203205
if size:
204206
try:

src/installer/sources.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
)
1717

1818
from installer.exceptions import InstallerError
19-
from installer.records import RecordEntry, parse_record_file
19+
from installer.records import InvalidRecordEntry, RecordEntry, parse_record_file
2020
from installer.utils import canonicalize_name, parse_wheel_filename
2121

2222
if TYPE_CHECKING:
@@ -277,7 +277,15 @@ def validate_record(self, *, validate_contents: bool = True) -> None:
277277
)
278278
continue
279279

280-
record = RecordEntry.from_elements(*record_args)
280+
try:
281+
record = RecordEntry.from_elements(*record_args)
282+
except InvalidRecordEntry as e:
283+
for issue in e.issues:
284+
issues.append(
285+
f"In {self._zipfile.filename}, entry in RECORD file for "
286+
f"{item.filename} is invalid: {issue}"
287+
)
288+
continue
281289

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

tests/test_sources.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -338,3 +338,26 @@ def test_rejects_record_validation_failed(self, fancy_wheel):
338338
),
339339
):
340340
source.validate_record()
341+
342+
def test_rejects_record_containing_unknown_hash(self, fancy_wheel):
343+
with WheelFile.open(fancy_wheel) as source:
344+
record_file_contents = source.read_dist_info("RECORD")
345+
346+
new_record_file_contents = record_file_contents.replace("sha256=", "sha=")
347+
replace_file_in_zip(
348+
fancy_wheel,
349+
filename="fancy-1.0.0.dist-info/RECORD",
350+
content=new_record_file_contents,
351+
)
352+
353+
with (
354+
WheelFile.open(fancy_wheel) as source,
355+
pytest.raises(
356+
WheelFile.validation_error,
357+
match=(
358+
"In .+, entry in RECORD file for .+ is invalid: "
359+
"invalid hash algorithm 'sha'"
360+
),
361+
),
362+
):
363+
source.validate_record(validate_contents=True)

0 commit comments

Comments
 (0)