Implement --index-strategy unsafe-best-match (#3138)

## Summary

This index strategy resolves every package to the latest possible
version across indexes. If a version is in multiple indexes, the first
available index is selected.

Implements #3137 

This closely matches pip.

## Test Plan

Good question. I'm hesitant to use my certifi example here, since that
would inevitably break when torch removes this package. Please comment!
This commit is contained in:
Yorick 2024-04-27 03:24:54 +02:00 committed by GitHub
parent a0e7d9fe87
commit 43181f1933
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 194 additions and 28 deletions

View file

@ -196,7 +196,7 @@ impl NoBuild {
}
}
#[derive(Debug, Default, Clone, Hash, Eq, PartialEq)]
#[derive(Debug, Default, Clone, Copy, Hash, Eq, PartialEq)]
#[cfg_attr(feature = "clap", derive(clap::ValueEnum))]
#[cfg_attr(feature = "serde", derive(serde::Deserialize))]
#[cfg_attr(
@ -210,7 +210,8 @@ pub enum IndexStrategy {
/// While this differs from pip's behavior, it's the default index strategy as it's the most
/// secure.
#[default]
FirstMatch,
#[cfg_attr(feature = "clap", clap(alias = "first-match"))]
FirstIndex,
/// Search for every package name across all indexes, exhausting the versions from the first
/// index before moving on to the next.
///
@ -222,7 +223,22 @@ pub enum IndexStrategy {
/// versions with different ABI tags or Python version constraints).
///
/// See: https://peps.python.org/pep-0708/
UnsafeAnyMatch,
#[cfg_attr(feature = "clap", clap(alias = "unsafe-any-match"))]
UnsafeFirstMatch,
/// Search for every package name across all indexes, preferring the "best" version found. If a
/// package version is in multiple indexes, only look at the entry for the first index.
///
/// In this strategy, we look for every package across all indexes. When resolving, we consider
/// all versions from all indexes, choosing the "best" version found (typically, the highest
/// compatible version).
///
/// This most closely matches pip's behavior, but exposes the resolver to "dependency confusion"
/// attacks whereby malicious actors can publish packages to public indexes with the same name
/// as internal packages, causing the resolver to install the malicious package in lieu of
/// the intended internal package.
///
/// See: https://peps.python.org/pep-0708/
UnsafeBestMatch,
}
#[cfg(test)]