Skip to content

Commit 9ad3b61

Browse files
authored
feat: Verify conda package's sha256 or md5 from pixi.lock (#260)
1 parent d1f9571 commit 9ad3b61

3 files changed

Lines changed: 30 additions & 3 deletions

File tree

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ futures = "0.3.31"
3737
indicatif = "0.18.3"
3838
rattler = { version = "0.39.5", default-features = false }
3939
rattler_config = "0.2.21"
40-
rattler_digest = "1.2.0"
40+
rattler_digest = { version = "1.2.0", features = ["tokio"] }
4141
rattler_conda_types = "0.42.2"
4242
rattler_index = "0.27.6"
4343
rattler_lock = "0.26.7"

src/pack.rs

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ use anyhow::Result;
2121
use base64::engine::{Engine, general_purpose::STANDARD};
2222
use futures::{StreamExt, TryFutureExt, TryStreamExt, stream};
2323
use rattler_conda_types::{ChannelInfo, PackageRecord, Platform, RepoData, package::ArchiveType};
24+
use rattler_digest::{HashingWriter, Md5, Sha256};
2425
use rattler_lock::{
2526
CondaBinaryData, CondaPackageData, LockFile, LockedPackageRef, PypiPackageData, UrlOrPath,
2627
};
@@ -433,6 +434,16 @@ fn reqwest_client_from_options(options: &PackOptions) -> Result<ClientWithMiddle
433434
Ok(client)
434435
}
435436

437+
async fn write_all_chunk<W>(response: &mut reqwest::Response, dest: &mut W) -> anyhow::Result<()>
438+
where
439+
W: tokio::io::AsyncWrite + Unpin,
440+
{
441+
while let Some(chunk) = response.chunk().await? {
442+
dest.write_all(&chunk).await?;
443+
}
444+
Ok(())
445+
}
446+
436447
/// Download a conda package to a given output directory.
437448
async fn download_package(
438449
client: &ClientWithMiddleware,
@@ -475,8 +486,23 @@ async fn download_package(
475486

476487
tracing::debug!("Fetching package {}", package.location);
477488
let mut response = client.get(url.clone()).send().await?.error_for_status()?;
478-
while let Some(chunk) = response.chunk().await? {
479-
dest.write_all(&chunk).await?;
489+
490+
if let Some(expected_sha) = package.package_record.sha256 {
491+
let mut dest = HashingWriter::<_, Sha256>::new(dest);
492+
write_all_chunk(&mut response, &mut dest).await?;
493+
let (_f, hash) = dest.finalize();
494+
if hash != expected_sha {
495+
anyhow::bail!("Download {file_name} failed, checksum mismatch");
496+
}
497+
} else if let Some(expected_md5) = package.package_record.md5 {
498+
let mut dest = HashingWriter::<_, Md5>::new(dest);
499+
write_all_chunk(&mut response, &mut dest).await?;
500+
let (_f, hash) = dest.finalize();
501+
if hash != expected_md5 {
502+
anyhow::bail!("Download {file_name} failed, checksum mismatch");
503+
}
504+
} else {
505+
write_all_chunk(&mut response, &mut dest).await?;
480506
}
481507
}
482508
}

0 commit comments

Comments
 (0)