From 3df8df656b07b7633cfc321ae88d4aad849495d8 Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Thu, 11 Apr 2024 20:41:08 -0400 Subject: [PATCH] Replace `unwrap` with `?` in hash generation (#3003) And add tests to catch it. --- crates/pypi-types/src/simple_json.rs | 2 +- crates/uv-types/src/hash.rs | 3 +- crates/uv/tests/pip_sync.rs | 66 ++++++++++++++++++++++++++++ 3 files changed, 68 insertions(+), 3 deletions(-) diff --git a/crates/pypi-types/src/simple_json.rs b/crates/pypi-types/src/simple_json.rs index 199b3c7c5..7750c8215 100644 --- a/crates/pypi-types/src/simple_json.rs +++ b/crates/pypi-types/src/simple_json.rs @@ -340,7 +340,7 @@ pub enum HashError { InvalidStructure(String), #[error( - "Unsupported hash algorithm (expected `md5`, `sha256`, `sha384`, or `sha512`) on: {0}" + "Unsupported hash algorithm: `{0}` (expected one of: `md5`, `sha256`, `sha384`, or `sha512`)" )] UnsupportedHashAlgorithm(String), } diff --git a/crates/uv-types/src/hash.rs b/crates/uv-types/src/hash.rs index 23b992b33..8cdee8268 100644 --- a/crates/uv-types/src/hash.rs +++ b/crates/uv-types/src/hash.rs @@ -141,8 +141,7 @@ impl HashStrategy { let digests = digests .iter() .map(|digest| HashDigest::from_str(digest)) - .collect::, _>>() - .unwrap(); + .collect::, _>>()?; hashes.insert(id, digests); } diff --git a/crates/uv/tests/pip_sync.rs b/crates/uv/tests/pip_sync.rs index 811a681f5..7cecbba56 100644 --- a/crates/uv/tests/pip_sync.rs +++ b/crates/uv/tests/pip_sync.rs @@ -3088,6 +3088,31 @@ requires-python = "<=3.5" Ok(()) } +/// Use an unknown hash algorithm with `--require-hashes`. +#[test] +fn require_hashes_unknown_algorithm() -> Result<()> { + let context = TestContext::new("3.12"); + + let requirements_txt = context.temp_dir.child("requirements.txt"); + requirements_txt.write_str( + "anyio==4.0.0 --hash=foo:cfdb2b588b9fc25ede96d8db56ed50848b0b649dca3dd1df0b11f683bb9e0b5f", + )?; + + uv_snapshot!(command(&context) + .arg("requirements.txt") + .arg("--require-hashes"), @r###" + success: false + exit_code: 2 + ----- stdout ----- + + ----- stderr ----- + error: Unsupported hash algorithm: `foo` (expected one of: `md5`, `sha256`, `sha384`, or `sha512`) + "### + ); + + Ok(()) +} + /// Omit the hash with `--require-hashes`. #[test] fn require_hashes_missing_hash() -> Result<()> { @@ -3168,6 +3193,47 @@ fn require_hashes_missing_version() -> Result<()> { Ok(()) } +/// Use a non-`==` operator with `--require-hashes`. +#[test] +fn require_hashes_invalid_operator() -> Result<()> { + let context = TestContext::new("3.12"); + + let requirements_txt = context.temp_dir.child("requirements.txt"); + requirements_txt.write_str( + "anyio>4.0.0 --hash=sha256:cfdb2b588b9fc25ede96d8db56ed50848b0b649dca3dd1df0b11f683bb9e0b5f", + )?; + + // Install without error when `--require-hashes` is omitted. + uv_snapshot!(command(&context) + .arg("requirements.txt"), @r###" + success: true + exit_code: 0 + ----- stdout ----- + + ----- stderr ----- + Resolved 1 package in [TIME] + Downloaded 1 package in [TIME] + Installed 1 package in [TIME] + + anyio==4.3.0 + "### + ); + + // Error when `--require-hashes` is provided. + uv_snapshot!(command(&context) + .arg("requirements.txt") + .arg("--require-hashes"), @r###" + success: false + exit_code: 2 + ----- stdout ----- + + ----- stderr ----- + error: In `--require-hashes` mode, all requirement must have their versions pinned with `==`, but found: anyio>4.0.0 + "### + ); + + Ok(()) +} + /// Include the hash for _just_ the wheel with `--no-binary`. #[test] fn require_hashes_wheel_no_binary() -> Result<()> {