mirror of
https://github.com/astral-sh/uv.git
synced 2025-10-28 10:50:29 +00:00
Make hash-checking failure mode stricter and safer (#2997)
## Summary If there are no hashes for a given package, we now return `Validate(&[])` so that the policy is impossible to satisfy. Previously, we returned `None`, which is always satisfied. We don't really ever expect to hit this, because we detect this case in the resolver and raise a different error. But if we have a bug somewhere, it's better to fail with an error than silently let the package through.
This commit is contained in:
parent
9d5467dc2f
commit
0d62e62fb7
2 changed files with 79 additions and 27 deletions
|
|
@ -88,12 +88,29 @@ pub enum Error {
|
||||||
HashExhaustion(#[source] std::io::Error),
|
HashExhaustion(#[source] std::io::Error),
|
||||||
|
|
||||||
#[error("Hash mismatch for {distribution}\n\nExpected:\n{expected}\n\nComputed:\n{actual}")]
|
#[error("Hash mismatch for {distribution}\n\nExpected:\n{expected}\n\nComputed:\n{actual}")]
|
||||||
HashMismatch {
|
MismatchedHashes {
|
||||||
distribution: String,
|
distribution: String,
|
||||||
expected: String,
|
expected: String,
|
||||||
actual: String,
|
actual: String,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
#[error(
|
||||||
|
"Hash-checking is enabled, but no hashes were provided or computed for: {distribution}"
|
||||||
|
)]
|
||||||
|
MissingHashes { distribution: String },
|
||||||
|
|
||||||
|
#[error("Hash-checking is enabled, but no hashes were computed for: {distribution}\n\nExpected:\n{expected}")]
|
||||||
|
MissingActualHashes {
|
||||||
|
distribution: String,
|
||||||
|
expected: String,
|
||||||
|
},
|
||||||
|
|
||||||
|
#[error("Hash-checking is enabled, but no hashes were provided for: {distribution}\n\nComputed:\n{actual}")]
|
||||||
|
MissingExpectedHashes {
|
||||||
|
distribution: String,
|
||||||
|
actual: String,
|
||||||
|
},
|
||||||
|
|
||||||
#[error("Hash-checking is not supported for local directories: {0}")]
|
#[error("Hash-checking is not supported for local directories: {0}")]
|
||||||
HashesNotSupportedSourceTree(String),
|
HashesNotSupportedSourceTree(String),
|
||||||
|
|
||||||
|
|
@ -125,22 +142,51 @@ impl Error {
|
||||||
expected: &[HashDigest],
|
expected: &[HashDigest],
|
||||||
actual: &[HashDigest],
|
actual: &[HashDigest],
|
||||||
) -> Error {
|
) -> Error {
|
||||||
let expected = expected
|
match (expected.is_empty(), actual.is_empty()) {
|
||||||
.iter()
|
(true, true) => Self::MissingHashes { distribution },
|
||||||
.map(|hash| format!(" {hash}"))
|
(true, false) => {
|
||||||
.collect::<Vec<_>>()
|
let actual = actual
|
||||||
.join("\n");
|
.iter()
|
||||||
|
.map(|hash| format!(" {hash}"))
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join("\n");
|
||||||
|
|
||||||
let actual = actual
|
Self::MissingExpectedHashes {
|
||||||
.iter()
|
distribution,
|
||||||
.map(|hash| format!(" {hash}"))
|
actual,
|
||||||
.collect::<Vec<_>>()
|
}
|
||||||
.join("\n");
|
}
|
||||||
|
(false, true) => {
|
||||||
|
let expected = expected
|
||||||
|
.iter()
|
||||||
|
.map(|hash| format!(" {hash}"))
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join("\n");
|
||||||
|
|
||||||
Self::HashMismatch {
|
Self::MissingActualHashes {
|
||||||
distribution,
|
distribution,
|
||||||
expected,
|
expected,
|
||||||
actual,
|
}
|
||||||
|
}
|
||||||
|
(false, false) => {
|
||||||
|
let expected = expected
|
||||||
|
.iter()
|
||||||
|
.map(|hash| format!(" {hash}"))
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join("\n");
|
||||||
|
|
||||||
|
let actual = actual
|
||||||
|
.iter()
|
||||||
|
.map(|hash| format!(" {hash}"))
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join("\n");
|
||||||
|
|
||||||
|
Self::MismatchedHashes {
|
||||||
|
distribution,
|
||||||
|
expected,
|
||||||
|
actual,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,10 +25,12 @@ impl HashStrategy {
|
||||||
match self {
|
match self {
|
||||||
Self::None => HashPolicy::None,
|
Self::None => HashPolicy::None,
|
||||||
Self::Generate => HashPolicy::Generate,
|
Self::Generate => HashPolicy::Generate,
|
||||||
Self::Validate(hashes) => hashes
|
Self::Validate(hashes) => HashPolicy::Validate(
|
||||||
.get(&distribution.package_id())
|
hashes
|
||||||
.map(Vec::as_slice)
|
.get(&distribution.package_id())
|
||||||
.map_or(HashPolicy::None, HashPolicy::Validate),
|
.map(Vec::as_slice)
|
||||||
|
.unwrap_or_default(),
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -37,10 +39,12 @@ impl HashStrategy {
|
||||||
match self {
|
match self {
|
||||||
Self::None => HashPolicy::None,
|
Self::None => HashPolicy::None,
|
||||||
Self::Generate => HashPolicy::Generate,
|
Self::Generate => HashPolicy::Generate,
|
||||||
Self::Validate(hashes) => hashes
|
Self::Validate(hashes) => HashPolicy::Validate(
|
||||||
.get(&PackageId::from_registry(name.clone()))
|
hashes
|
||||||
.map(Vec::as_slice)
|
.get(&PackageId::from_registry(name.clone()))
|
||||||
.map_or(HashPolicy::None, HashPolicy::Validate),
|
.map(Vec::as_slice)
|
||||||
|
.unwrap_or_default(),
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -49,10 +53,12 @@ impl HashStrategy {
|
||||||
match self {
|
match self {
|
||||||
Self::None => HashPolicy::None,
|
Self::None => HashPolicy::None,
|
||||||
Self::Generate => HashPolicy::Generate,
|
Self::Generate => HashPolicy::Generate,
|
||||||
Self::Validate(hashes) => hashes
|
Self::Validate(hashes) => HashPolicy::Validate(
|
||||||
.get(&PackageId::from_url(url))
|
hashes
|
||||||
.map(Vec::as_slice)
|
.get(&PackageId::from_url(url))
|
||||||
.map_or(HashPolicy::None, HashPolicy::Validate),
|
.map(Vec::as_slice)
|
||||||
|
.unwrap_or_default(),
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue