Skip to content

Commit

Permalink
Improve error handling on FIPS systems (python-poetry#9152)
Browse files Browse the repository at this point in the history
  • Loading branch information
PabloAlexis611 committed Mar 18, 2024
1 parent 1b0caf5 commit 52b113d
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 1 deletion.
7 changes: 6 additions & 1 deletion src/poetry/repositories/http_repository.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import hashlib

from contextlib import contextmanager
from contextlib import suppress
from pathlib import Path
from typing import TYPE_CHECKING
from typing import Any
Expand Down Expand Up @@ -374,7 +375,11 @@ def calculate_sha256(self, link: Link) -> str | None:
hash_name = get_highest_priority_hash_type(
set(link.hashes.keys()), link.filename
)
known_hash = getattr(hashlib, hash_name)() if hash_name else None
known_hash = None
with suppress(ValueError, AttributeError):
# Handle ValueError here as well since under FIPS environments
# this is what is raised (e.g., for MD5)
known_hash = getattr(hashlib, hash_name)() if hash_name else None
required_hash = hashlib.sha256()

chunksize = 4096
Expand Down
68 changes: 68 additions & 0 deletions tests/repositories/test_http_repository.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,3 +153,71 @@ def test_get_info_from_wheel_state_sequence(mocker: MockerFixture) -> None:
repo._get_info_from_wheel(link)
assert mock_metadata_from_wheel_url.call_count == 5
assert mock_download.call_count == 4


@pytest.mark.parametrize(
"mock_hashes",
[
None,
{"sha256": "e216b70f013c47b82a72540d34347632c5bfe59fd54f5fe5d51f6a68b19aaf84"},
{"md5": "be7589b4902793e66d7d979bd8581591"},
],
)
def test_calculate_sha256(
mocker: MockerFixture, mock_hashes: dict[str, Any] | None
) -> None:
filename = "poetry_core-1.5.0-py3-none-any.whl"
filepath = MockRepository.DIST_FIXTURES / filename
mock_download = mocker.patch(
"poetry.repositories.http_repository.download_file",
side_effect=lambda _, dest, *args, **kwargs: shutil.copy(filepath, dest),
)
domain = "foo.com"
link = Link(f"https://{domain}/{filename}", hashes=mock_hashes)
repo = MockRepository()

calculated_hash = repo.calculate_sha256(link)

assert mock_download.call_count == 1
assert (
calculated_hash
== "sha256:e216b70f013c47b82a72540d34347632c5bfe59fd54f5fe5d51f6a68b19aaf84"
)


def test_calculate_sha256_defaults_to_sha256_on_md5_errors(
mocker: MockerFixture,
) -> None:
raised_value_error = False

def mock_hashlib_md5_error() -> None:
nonlocal raised_value_error
raised_value_error = True
raise ValueError(
"[digital envelope routines: EVP_DigestInit_ex] disabled for FIPS"
)

filename = "poetry_core-1.5.0-py3-none-any.whl"
filepath = MockRepository.DIST_FIXTURES / filename
mock_download = mocker.patch(
"poetry.repositories.http_repository.download_file",
side_effect=lambda _, dest, *args, **kwargs: shutil.copy(filepath, dest),
)
mock_hashlib_md5 = mocker.patch("hashlib.md5", side_effect=mock_hashlib_md5_error)

domain = "foo.com"
link = Link(
f"https://{domain}/{filename}",
hashes={"md5": "be7589b4902793e66d7d979bd8581591"},
)
repo = MockRepository()

calculated_hash = repo.calculate_sha256(link)

assert raised_value_error
assert mock_download.call_count == 1
assert mock_hashlib_md5.call_count == 1
assert (
calculated_hash
== "sha256:e216b70f013c47b82a72540d34347632c5bfe59fd54f5fe5d51f6a68b19aaf84"
)

0 comments on commit 52b113d

Please sign in to comment.