Commit c719dced by Bernát Gábor Committed by GitHub

Support non SHA256/SHA384/SHA512 HTTPRepository (#8118)

Signed-off-by: Bernát Gábor <bgabor8@bloomberg.net>
parent fedff6da
...@@ -8,6 +8,7 @@ from typing import Any ...@@ -8,6 +8,7 @@ from typing import Any
from poetry.config.config import Config from poetry.config.config import Config
from poetry.config.config import PackageFilterPolicy from poetry.config.config import PackageFilterPolicy
from poetry.repositories.http_repository import HTTPRepository
from poetry.utils.wheel import Wheel from poetry.utils.wheel import Wheel
...@@ -103,6 +104,12 @@ class Chooser: ...@@ -103,6 +104,12 @@ class Chooser:
assert link.hash_name is not None assert link.hash_name is not None
h = link.hash_name + ":" + link.hash h = link.hash_name + ":" + link.hash
if (
h not in hashes
and link.hash_name not in ("sha256", "sha384", "sha512")
and isinstance(repository, HTTPRepository)
):
h = repository.calculate_sha256(link) or h
if h not in hashes: if h not in hashes:
logger.debug( logger.debug(
"Skipping %s as %s checksum does not match expected value", "Skipping %s as %s checksum does not match expected value",
......
...@@ -226,24 +226,7 @@ class HTTPRepository(CachedRepository): ...@@ -226,24 +226,7 @@ class HTTPRepository(CachedRepository):
and link.hash_name not in ("sha256", "sha384", "sha512") and link.hash_name not in ("sha256", "sha384", "sha512")
and hasattr(hashlib, link.hash_name) and hasattr(hashlib, link.hash_name)
): ):
with self._cached_or_downloaded_file(link) as filepath: file_hash = self.calculate_sha256(link) or file_hash
known_hash = (
getattr(hashlib, link.hash_name)() if link.hash_name else None
)
required_hash = hashlib.sha256()
chunksize = 4096
with filepath.open("rb") as f:
while True:
chunk = f.read(chunksize)
if not chunk:
break
if known_hash:
known_hash.update(chunk)
required_hash.update(chunk)
if not known_hash or known_hash.hexdigest() == link.hash:
file_hash = f"{required_hash.name}:{required_hash.hexdigest()}"
files.append({"file": link.filename, "hash": file_hash}) files.append({"file": link.filename, "hash": file_hash})
...@@ -257,6 +240,25 @@ class HTTPRepository(CachedRepository): ...@@ -257,6 +240,25 @@ class HTTPRepository(CachedRepository):
return data.asdict() return data.asdict()
def calculate_sha256(self, link: Link) -> str | None:
with self._cached_or_downloaded_file(link) as filepath:
known_hash = getattr(hashlib, link.hash_name)() if link.hash_name else None
required_hash = hashlib.sha256()
chunksize = 4096
with filepath.open("rb") as f:
while True:
chunk = f.read(chunksize)
if not chunk:
break
if known_hash:
known_hash.update(chunk)
required_hash.update(chunk)
if not known_hash or known_hash.hexdigest() == link.hash:
return f"{required_hash.name}:{required_hash.hexdigest()}"
return None
def _get_response(self, endpoint: str) -> requests.Response | None: def _get_response(self, endpoint: str) -> requests.Response | None:
url = self._url + endpoint url = self._url + endpoint
try: try:
......
...@@ -36,6 +36,7 @@ if TYPE_CHECKING: ...@@ -36,6 +36,7 @@ if TYPE_CHECKING:
from poetry.installation.operations.operation import Operation from poetry.installation.operations.operation import Operation
from poetry.poetry import Poetry from poetry.poetry import Poetry
from poetry.utils.authenticator import Authenticator
FIXTURE_PATH = Path(__file__).parent / "fixtures" FIXTURE_PATH = Path(__file__).parent / "fixtures"
...@@ -120,7 +121,7 @@ def mock_clone( ...@@ -120,7 +121,7 @@ def mock_clone(
return MockDulwichRepo(dest) return MockDulwichRepo(dest)
def mock_download(url: str, dest: Path) -> None: def mock_download(url: str, dest: Path, session: Authenticator | None = None) -> None:
parts = urllib.parse.urlparse(url) parts = urllib.parse.urlparse(url)
fixture = FIXTURE_PATH / parts.path.lstrip("/") fixture = FIXTURE_PATH / parts.path.lstrip("/")
......
...@@ -405,3 +405,25 @@ def test_chooser_throws_an_error_if_package_hashes_do_not_match( ...@@ -405,3 +405,25 @@ def test_chooser_throws_an_error_if_package_hashes_do_not_match(
with pytest.raises(RuntimeError) as e: with pytest.raises(RuntimeError) as e:
chooser.choose_for(package) chooser.choose_for(package)
assert files[0]["hash"] in str(e) assert files[0]["hash"] in str(e)
@pytest.mark.usefixtures("mock_legacy")
def test_chooser_md5_remote_fallback_to_sha256_inline_calculation(
env: MockEnv, pool: RepositoryPool
) -> None:
chooser = Chooser(pool, env)
package = Package(
"demo",
"0.1.0",
source_type="legacy",
source_reference="foo",
source_url="https://foo.bar/simple/",
)
package.files = [
{
"hash": "sha256:9fa123ad707a5c6c944743bf3e11a0e80d86cb518d3cf25320866ca3ef43e2ad", # noqa: E501
"filename": "demo-0.1.0.tar.gz",
}
]
res = chooser.choose_for(package)
assert res.filename == "demo-0.1.0.tar.gz"
<html>
<head><title>Simple Index</title><meta name="api-version" value="2" /></head>
<body>
<a href="https://files.pythonhosted.org/distributions/demo-0.1.0.tar.gz#md5=d1912c917363a64e127318655f7d1fe7" rel="internal">demo-0.1.0.tar.gz</a><br/>
</body>
</html>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment