mirror of https://github.com/pypa/pip
Compare commits
12 Commits
4a103b80f9
...
9dcbde7cb1
Author | SHA1 | Date |
---|---|---|
Stéphane Bidoul | 9dcbde7cb1 | |
Tzu-ping Chung | a15dd75d98 | |
Tzu-ping Chung | d8ab6dc6c1 | |
Qiming Xu | fe10d368f6 | |
Qiming Xu | 28250baffb | |
Qiming Xu | 88ac529219 | |
Stéphane Bidoul | 8003490440 | |
Stéphane Bidoul | c59af71f40 | |
Stéphane Bidoul | 7aab44cc06 | |
Stéphane Bidoul | a1cd61b4fc | |
Stéphane Bidoul | 88ac144288 | |
Stéphane Bidoul | 061d3e9c5d |
|
@ -45,8 +45,8 @@ When looking at the items to be installed, pip checks what type of item
|
|||
each is, in the following order:
|
||||
|
||||
1. Project or archive URL.
|
||||
2. Local directory (which must contain a ``setup.py``, or pip will report
|
||||
an error).
|
||||
2. Local directory (which must contain a ``pyproject.toml`` or ``setup.py``,
|
||||
otherwise pip will report an error).
|
||||
3. Local file (a sdist or wheel format archive, following the naming
|
||||
conventions for those formats).
|
||||
4. A requirement, as specified in :pep:`440`.
|
||||
|
|
|
@ -43,6 +43,12 @@ FooProject == 1.2 \
|
|||
|
||||
This prevents a surprising hash mismatch upon the release of a new version that matches the requirement specifier.
|
||||
|
||||
```{versionadded} 23.2
|
||||
VCS URLs that reference a commit hash are now supported in hash checking mode,
|
||||
since pip now trusts that the VCS provides the required source immutability guarantees.
|
||||
This is currently only supported with `git` URLs.
|
||||
```
|
||||
|
||||
### Forcing Hash-checking mode
|
||||
|
||||
It is possible to force the hash checking mode to be enabled, by passing `--require-hashes` command-line option.
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Fix outdated pip install argument description in documentation.
|
|
@ -0,0 +1 @@
|
|||
Validate VCS urls in hash-checking mode using their commit hashes.
|
|
@ -498,6 +498,32 @@ class VcsHashUnsupported(HashError):
|
|||
)
|
||||
|
||||
|
||||
class CacheEntryTypeHashNotSupported(HashError):
|
||||
"""A wheel cache entry was built from a URL that does not support hash checking."""
|
||||
|
||||
order = 0
|
||||
head = (
|
||||
"Can't verify hashes for these cached requirements because they are "
|
||||
"from a URL that does not support hash checking:"
|
||||
)
|
||||
|
||||
|
||||
class DependencyVcsHashNotSupported(HashError):
|
||||
order = 0
|
||||
head = (
|
||||
"Can't verify hashes for these VCS requirements because they are "
|
||||
"not user supplied, so we don't assume their VCS ref is trusted:"
|
||||
)
|
||||
|
||||
|
||||
class MutableVcsRefHashNotSupported(HashError):
|
||||
order = 0
|
||||
head = (
|
||||
"Can't verify hashes for these VCS requirements because their ref "
|
||||
"is not immutable:"
|
||||
)
|
||||
|
||||
|
||||
class DirectoryUrlHashUnsupported(HashError):
|
||||
"""A hash was provided for a version-control-system-based requirement, but
|
||||
we don't have a method for hashing those."""
|
||||
|
|
|
@ -15,17 +15,20 @@ from pip._vendor.packaging.utils import canonicalize_name
|
|||
from pip._internal.distributions import make_distribution_for_install_requirement
|
||||
from pip._internal.distributions.installed import InstalledDistribution
|
||||
from pip._internal.exceptions import (
|
||||
CacheEntryTypeHashNotSupported,
|
||||
DependencyVcsHashNotSupported,
|
||||
DirectoryUrlHashUnsupported,
|
||||
HashMismatch,
|
||||
HashUnpinned,
|
||||
InstallationError,
|
||||
MetadataInconsistent,
|
||||
MutableVcsRefHashNotSupported,
|
||||
NetworkConnectionError,
|
||||
VcsHashUnsupported,
|
||||
)
|
||||
from pip._internal.index.package_finder import PackageFinder
|
||||
from pip._internal.metadata import BaseDistribution, get_metadata_distribution
|
||||
from pip._internal.models.direct_url import ArchiveInfo
|
||||
from pip._internal.models.direct_url import ArchiveInfo, VcsInfo
|
||||
from pip._internal.models.link import Link
|
||||
from pip._internal.models.wheel import Wheel
|
||||
from pip._internal.network.download import BatchDownloader, Downloader
|
||||
|
@ -41,7 +44,7 @@ from pip._internal.utils.direct_url_helpers import (
|
|||
direct_url_for_editable,
|
||||
direct_url_from_link,
|
||||
)
|
||||
from pip._internal.utils.hashes import Hashes, MissingHashes
|
||||
from pip._internal.utils.hashes import Hashes, MissingHashes, VcsHashes
|
||||
from pip._internal.utils.logging import indent_log
|
||||
from pip._internal.utils.misc import (
|
||||
display_path,
|
||||
|
@ -74,10 +77,14 @@ def _get_prepared_distribution(
|
|||
return abstract_dist.get_metadata_distribution()
|
||||
|
||||
|
||||
def unpack_vcs_link(link: Link, location: str, verbosity: int) -> None:
|
||||
def unpack_vcs_link(
|
||||
link: Link, location: str, verbosity: int, hashes: Optional[Hashes] = None
|
||||
) -> None:
|
||||
vcs_backend = vcs.get_backend_for_scheme(link.scheme)
|
||||
assert vcs_backend is not None
|
||||
vcs_backend.unpack(location, url=hide_url(link.url), verbosity=verbosity)
|
||||
if hashes and not vcs_backend.is_immutable_rev_checkout(link.url, location):
|
||||
raise MutableVcsRefHashNotSupported()
|
||||
|
||||
|
||||
class File:
|
||||
|
@ -154,7 +161,7 @@ def unpack_url(
|
|||
"""
|
||||
# non-editable vcs urls
|
||||
if link.is_vcs:
|
||||
unpack_vcs_link(link, location, verbosity=verbosity)
|
||||
unpack_vcs_link(link, location, verbosity=verbosity, hashes=hashes)
|
||||
return None
|
||||
|
||||
assert not link.is_existing_dir()
|
||||
|
@ -327,6 +334,14 @@ class RequirementPreparer:
|
|||
# and raise some more informative errors than otherwise.
|
||||
# (For example, we can raise VcsHashUnsupported for a VCS URL
|
||||
# rather than HashMissing.)
|
||||
|
||||
# Check that --hash is not used with VCS and local directory direct URLs.
|
||||
if req.original_link:
|
||||
if req.original_link.is_vcs and req.hashes(trust_internet=False):
|
||||
raise VcsHashUnsupported()
|
||||
if req.original_link.is_existing_dir() and req.hashes(trust_internet=False):
|
||||
raise DirectoryUrlHashUnsupported()
|
||||
|
||||
if not self.require_hashes:
|
||||
return req.hashes(trust_internet=True)
|
||||
|
||||
|
@ -335,7 +350,9 @@ class RequirementPreparer:
|
|||
# report less-useful error messages for unhashable
|
||||
# requirements, complaining that there's no hash provided.
|
||||
if req.link.is_vcs:
|
||||
raise VcsHashUnsupported()
|
||||
if not req.user_supplied:
|
||||
raise DependencyVcsHashNotSupported()
|
||||
return VcsHashes()
|
||||
if req.link.is_existing_dir():
|
||||
raise DirectoryUrlHashUnsupported()
|
||||
|
||||
|
@ -568,24 +585,33 @@ class RequirementPreparer:
|
|||
assert link.is_file
|
||||
# We need to verify hashes, and we have found the requirement in the cache
|
||||
# of locally built wheels.
|
||||
if (
|
||||
isinstance(req.download_info.info, ArchiveInfo)
|
||||
and req.download_info.info.hashes
|
||||
and hashes.has_one_of(req.download_info.info.hashes)
|
||||
):
|
||||
# At this point we know the requirement was built from a hashable source
|
||||
# artifact, and we verified that the cache entry's hash of the original
|
||||
# artifact matches one of the hashes we expect. We don't verify hashes
|
||||
# against the cached wheel, because the wheel is not the original.
|
||||
if isinstance(req.download_info.info, ArchiveInfo):
|
||||
if req.download_info.info.hashes and hashes.has_one_of(
|
||||
req.download_info.info.hashes
|
||||
):
|
||||
# At this point we know the requirement was built from a hashable
|
||||
# source artifact, and we verified that the cache entry's hash of
|
||||
# the original artifact matches one of the hashes we expect. We
|
||||
# don't verify hashes against the cached wheel, because the wheel is
|
||||
# not the original.
|
||||
hashes = None
|
||||
else:
|
||||
logger.warning(
|
||||
"The hashes of the source archive found in cache entry "
|
||||
"don't match, ignoring cached built wheel "
|
||||
"and re-downloading source."
|
||||
)
|
||||
req.link = req.cached_wheel_source_link
|
||||
link = req.link
|
||||
elif isinstance(req.download_info.info, VcsInfo):
|
||||
if not req.user_supplied:
|
||||
raise DependencyVcsHashNotSupported()
|
||||
# Don't verify hashes against the cached wheel: if it is in cache,
|
||||
# it means it was built from a URL referencing an immutable commit
|
||||
# hash.
|
||||
hashes = None
|
||||
else:
|
||||
logger.warning(
|
||||
"The hashes of the source archive found in cache entry "
|
||||
"don't match, ignoring cached built wheel "
|
||||
"and re-downloading source."
|
||||
)
|
||||
req.link = req.cached_wheel_source_link
|
||||
link = req.link
|
||||
raise CacheEntryTypeHashNotSupported()
|
||||
|
||||
self._ensure_link_req_src_dir(req, parallel_builds)
|
||||
|
||||
|
|
|
@ -293,7 +293,7 @@ class InstallRequirement:
|
|||
"""
|
||||
return bool(self.hash_options)
|
||||
|
||||
def hashes(self, trust_internet: bool = True) -> Hashes:
|
||||
def hashes(self, *, trust_internet: bool) -> Hashes:
|
||||
"""Return a hash-comparer that considers my option- and URL-based
|
||||
hashes to be known-good.
|
||||
|
||||
|
|
|
@ -149,3 +149,13 @@ class MissingHashes(Hashes):
|
|||
|
||||
def _raise(self, gots: Dict[str, "_Hash"]) -> "NoReturn":
|
||||
raise HashMissing(gots[FAVORITE_HASH].hexdigest())
|
||||
|
||||
|
||||
class VcsHashes(MissingHashes):
|
||||
"""A workalike for Hashes used for VCS references
|
||||
|
||||
It never matches, and is used as a sentinel to indicate that we should
|
||||
check the VCS reference is an immutable commit reference.
|
||||
"""
|
||||
|
||||
pass
|
||||
|
|
|
@ -208,7 +208,7 @@ class TestRequirementSet:
|
|||
reqset = RequirementSet()
|
||||
reqset.add_unnamed_requirement(
|
||||
get_processed_req_from_line(
|
||||
"git+git://github.com/pypa/pip-test-package --hash=sha256:123",
|
||||
"git+https://github.com/pypa/pip-test-package --hash=sha256:123",
|
||||
lineno=1,
|
||||
)
|
||||
)
|
||||
|
@ -231,7 +231,7 @@ class TestRequirementSet:
|
|||
match=(
|
||||
r"Can't verify hashes for these requirements because we don't "
|
||||
r"have a way to hash version control repositories:\n"
|
||||
r" git\+git://github\.com/pypa/pip-test-package \(from -r "
|
||||
r" git\+https://github\.com/pypa/pip-test-package \(from -r "
|
||||
r"file \(line 1\)\)\n"
|
||||
r"Can't verify hashes for these file:// requirements because "
|
||||
r"they point to directories:\n"
|
||||
|
|
Loading…
Reference in New Issue