-
Notifications
You must be signed in to change notification settings - Fork 760
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add hash-checking support to install
and sync
#2945
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
use pypi_types::HashDigest; | ||
|
||
pub trait Hashed { | ||
/// Return the [`HashDigest`]s for the archive. | ||
fn hashes(&self) -> &[HashDigest]; | ||
|
||
/// Returns `true` if the archive satisfies the given hashes. | ||
fn satisfies(&self, hashes: &[HashDigest]) -> bool { | ||
if hashes.is_empty() { | ||
true | ||
} else { | ||
self.hashes().iter().any(|hash| hashes.contains(hash)) | ||
} | ||
} | ||
|
||
/// Returns `true` if the archive includes a hash for at least one of the given algorithms. | ||
fn has_digests(&self, hashes: &[HashDigest]) -> bool { | ||
if hashes.is_empty() { | ||
true | ||
} else { | ||
hashes | ||
.iter() | ||
.map(HashDigest::algorithm) | ||
.any(|algorithm| self.hashes().iter().any(|hash| hash.algorithm == algorithm)) | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -84,6 +84,8 @@ impl Display for IncompatibleDist { | |
IncompatibleWheel::RequiresPython(python) => { | ||
write!(f, "it requires at python {python}") | ||
} | ||
IncompatibleWheel::MissingHash => f.write_str("it has no hash"), | ||
IncompatibleWheel::MismatchedHash => f.write_str("the hash does not match"), | ||
}, | ||
Self::Source(incompatibility) => match incompatibility { | ||
IncompatibleSource::NoBuild => { | ||
|
@@ -104,6 +106,8 @@ impl Display for IncompatibleDist { | |
IncompatibleSource::RequiresPython(python) => { | ||
write!(f, "it requires python {python}") | ||
} | ||
IncompatibleSource::MissingHash => f.write_str("it has no hash"), | ||
IncompatibleSource::MismatchedHash => f.write_str("the hash does not match"), | ||
}, | ||
Self::Unavailable => f.write_str("no distributions are available"), | ||
} | ||
|
@@ -122,6 +126,8 @@ pub enum IncompatibleWheel { | |
Tag(IncompatibleTag), | ||
RequiresPython(VersionSpecifiers), | ||
Yanked(Yanked), | ||
MissingHash, | ||
MismatchedHash, | ||
NoBinary, | ||
} | ||
|
||
|
@@ -136,6 +142,8 @@ pub enum IncompatibleSource { | |
ExcludeNewer(Option<i64>), | ||
RequiresPython(VersionSpecifiers), | ||
Yanked(Yanked), | ||
MissingHash, | ||
MismatchedHash, | ||
NoBuild, | ||
} | ||
|
||
|
@@ -381,20 +389,26 @@ impl IncompatibleSource { | |
Self::ExcludeNewer(timestamp_self) => match other { | ||
// Smaller timestamps are closer to the cut-off time | ||
Self::ExcludeNewer(timestamp_other) => timestamp_other < timestamp_self, | ||
Self::NoBuild | Self::RequiresPython(_) | Self::Yanked(_) => true, | ||
Self::NoBuild | ||
| Self::RequiresPython(_) | ||
| Self::Yanked(_) | ||
| Self::MissingHash | ||
| Self::MismatchedHash => true, | ||
}, | ||
Self::RequiresPython(_) => match other { | ||
Self::ExcludeNewer(_) => false, | ||
// Version specifiers cannot be reasonably compared | ||
Self::RequiresPython(_) => false, | ||
Self::NoBuild | Self::Yanked(_) => true, | ||
Self::NoBuild | Self::Yanked(_) | Self::MissingHash | Self::MismatchedHash => true, | ||
}, | ||
Self::Yanked(_) => match other { | ||
Self::ExcludeNewer(_) | Self::RequiresPython(_) => false, | ||
// Yanks with a reason are more helpful for errors | ||
Self::Yanked(yanked_other) => matches!(yanked_other, Yanked::Reason(_)), | ||
Self::NoBuild => true, | ||
Self::NoBuild | Self::MissingHash | Self::MismatchedHash => true, | ||
}, | ||
Self::MissingHash => false, | ||
Self::MismatchedHash => false, | ||
Self::NoBuild => false, | ||
} | ||
} | ||
|
@@ -412,26 +426,37 @@ impl IncompatibleWheel { | |
timestamp_other < timestamp_self | ||
} | ||
}, | ||
Self::NoBinary | Self::RequiresPython(_) | Self::Tag(_) | Self::Yanked(_) => true, | ||
Self::NoBinary | ||
| Self::RequiresPython(_) | ||
| Self::Tag(_) | ||
| Self::Yanked(_) | ||
| Self::MissingHash | ||
| Self::MismatchedHash => true, | ||
}, | ||
Self::Tag(tag_self) => match other { | ||
Self::ExcludeNewer(_) => false, | ||
Self::Tag(tag_other) => tag_other > tag_self, | ||
Self::NoBinary | Self::RequiresPython(_) | Self::Yanked(_) => true, | ||
Self::NoBinary | ||
| Self::RequiresPython(_) | ||
| Self::Yanked(_) | ||
| Self::MissingHash | ||
| Self::MismatchedHash => true, | ||
}, | ||
Self::RequiresPython(_) => match other { | ||
Self::ExcludeNewer(_) | Self::Tag(_) => false, | ||
// Version specifiers cannot be reasonably compared | ||
Self::RequiresPython(_) => false, | ||
Self::NoBinary | Self::Yanked(_) => true, | ||
Self::NoBinary | Self::Yanked(_) | Self::MissingHash | Self::MismatchedHash => true, | ||
}, | ||
Self::Yanked(_) => match other { | ||
Self::ExcludeNewer(_) | Self::Tag(_) | Self::RequiresPython(_) => false, | ||
// Yanks with a reason are more helpful for errors | ||
Self::Yanked(yanked_other) => matches!(yanked_other, Yanked::Reason(_)), | ||
Self::NoBinary => true, | ||
Self::NoBinary | Self::MissingHash | Self::MismatchedHash => true, | ||
}, | ||
Self::NoBinary => false, | ||
Self::MismatchedHash => false, | ||
Self::MissingHash => false, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @zanieb - I could use your help with this part. I'm not sure if I did the comparisons correctly here. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this is actually wrong, although I'm not sure if it matters. You're supposed to be enforcing an ordering but here you're saying that There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I decided to change up the strategy in #2949, such that we treat distributions without hashes as compatible (but lower-priority). I can merge that into this PR if you agree with the change. |
||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we want to support md5? It's cryptographically broken