From ab09bee7d65040eef6116588495f2db7926a38d0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 10 Jul 2026 19:38:25 +0000 Subject: [PATCH 1/2] chore(deps): bump sha2 Bumps the dependencies-major group with 1 update in the /src-tauri directory: [sha2](https://github.com/RustCrypto/hashes). Updates `sha2` from 0.10.9 to 0.11.0 - [Commits](https://github.com/RustCrypto/hashes/compare/sha2-v0.10.9...sha2-v0.11.0) --- updated-dependencies: - dependency-name: sha2 dependency-version: 0.11.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: dependencies-major ... Signed-off-by: dependabot[bot] --- src-tauri/Cargo.lock | 82 +++++++++++++++++++++++++++++++++++++++----- src-tauri/Cargo.toml | 2 +- 2 files changed, 74 insertions(+), 10 deletions(-) diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 00190d21..953b5974 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -185,6 +185,15 @@ dependencies = [ "generic-array", ] +[[package]] +name = "block-buffer" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2f6c7dbe95a6ed67ad9f18e57daf93a2f034c524b99fd2b76d18fdfeb6660aa" +dependencies = [ + "hybrid-array", +] + [[package]] name = "block2" version = "0.6.2" @@ -412,6 +421,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "const-oid" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c" + [[package]] name = "cookie" version = "0.18.1" @@ -481,6 +496,15 @@ dependencies = [ "libc", ] +[[package]] +name = "cpufeatures" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" +dependencies = [ + "libc", +] + [[package]] name = "crc32fast" version = "1.5.0" @@ -515,6 +539,15 @@ dependencies = [ "typenum", ] +[[package]] +name = "crypto-common" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453" +dependencies = [ + "hybrid-array", +] + [[package]] name = "cssparser" version = "0.36.0" @@ -664,8 +697,19 @@ version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ - "block-buffer", - "crypto-common", + "block-buffer 0.10.4", + "crypto-common 0.1.7", +] + +[[package]] +name = "digest" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2" +dependencies = [ + "block-buffer 0.12.1", + "const-oid", + "crypto-common 0.2.2", ] [[package]] @@ -1531,6 +1575,15 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" +[[package]] +name = "hybrid-array" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "818356c5132c1fede50f837ca96afbe78ff42413047f4abb886217845e1b6c8c" +dependencies = [ + "typenum", +] + [[package]] name = "hyper" version = "1.8.1" @@ -3619,8 +3672,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", - "cpufeatures", - "digest", + "cpufeatures 0.2.17", + "digest 0.10.7", +] + +[[package]] +name = "sha2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "446ba717509524cb3f22f17ecc096f10f4822d76ab5c0b9822c5f9c284e825f4" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.0", + "digest 0.11.3", ] [[package]] @@ -4026,7 +4090,7 @@ dependencies = [ "semver", "serde", "serde_json", - "sha2", + "sha2 0.10.9", "syn 2.0.117", "tauri-utils", "thiserror 2.0.18", @@ -4342,7 +4406,7 @@ dependencies = [ "semver", "serde", "serde_json", - "sha2", + "sha2 0.11.0", "tauri", "tauri-build", "tauri-nspanel", @@ -4686,9 +4750,9 @@ checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c" [[package]] name = "typenum" -version = "1.19.0" +version = "1.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" +checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" [[package]] name = "unic-char-property" @@ -5750,7 +5814,7 @@ dependencies = [ "once_cell", "percent-encoding", "raw-window-handle", - "sha2", + "sha2 0.10.9", "soup3", "tao-macros", "thiserror 2.0.18", diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 856907b8..20250bd8 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -43,7 +43,7 @@ thiserror = "2" time = { version = "0.3", features = ["std"] } async-trait = "0.1" semver = "1" -sha2 = "0.10" +sha2 = "0.11" libc = "0.2" keyring = { version = "3", features = ["apple-native"] } From d5869849c512078704f1878a17ef1c14892fef0b Mon Sep 17 00:00:00 2001 From: Logan Nguyen Date: Mon, 13 Jul 2026 01:19:47 -0500 Subject: [PATCH 2/2] fix: update sha2 0.11 finalize() hex formatting Signed-off-by: Logan Nguyen --- src-tauri/src/models/download.rs | 10 ++++---- src-tauri/src/models/storage.rs | 41 ++++++++++++++++++++++++++++---- 2 files changed, 43 insertions(+), 8 deletions(-) diff --git a/src-tauri/src/models/download.rs b/src-tauri/src/models/download.rs index b307a934..ca8b748b 100644 --- a/src-tauri/src/models/download.rs +++ b/src-tauri/src/models/download.rs @@ -28,7 +28,7 @@ use futures_util::StreamExt; use tokio::sync::Semaphore; use tokio_util::sync::CancellationToken; -use super::storage::{ModelStore, StorageError}; +use super::storage::{hex_digest, HashWriter, ModelStore, StorageError}; use crate::config::defaults::DOWNLOAD_PROGRESS_MIN_INTERVAL_MS; /// Progress events streamed to the frontend while a model downloads. @@ -628,7 +628,9 @@ async fn fetch_into_partial( file: spec.file.clone(), }); store - .feed_partial(&spec.sha256, &mut hasher, &|| cancel.is_cancelled()) + .feed_partial(&spec.sha256, &mut HashWriter(&mut hasher), &|| { + cancel.is_cancelled() + }) .map_err(DownloadIoError::Write)?; } } @@ -698,7 +700,7 @@ async fn fetch_into_partial( } file.flush().map_err(DownloadIoError::Write)?; Ok(FetchOutcome::Done { - sha256: format!("{:x}", hasher.finalize()), + sha256: hex_digest(&hasher.finalize()), }) } @@ -824,7 +826,7 @@ mod tests { /// Compute the hex SHA-256 of `data`. fn sha256_of(data: &[u8]) -> String { - format!("{:x}", Sha256::digest(data)) + hex_digest(&Sha256::digest(data)) } /// Event sink: returns the shared event log and an `emit` closure. diff --git a/src-tauri/src/models/storage.rs b/src-tauri/src/models/storage.rs index cc6ec6c1..8adf6339 100644 --- a/src-tauri/src/models/storage.rs +++ b/src-tauri/src/models/storage.rs @@ -25,6 +25,27 @@ use sha2::{Digest, Sha256}; use super::HfGgufPart; use crate::config::defaults::BLOB_HASH_BUFFER_BYTES; +/// Renders a SHA-256 digest as a lowercase hex string. +pub(crate) fn hex_digest(bytes: &[u8]) -> String { + bytes.iter().map(|b| format!("{b:02x}")).collect() +} + +/// Adapts a [`Digest`] hasher to [`io::Write`] so it can be used as a +/// [`ModelStore::feed_partial`] sink. sha2 0.11 dropped hashers' own `Write` +/// impl; this forwards each write straight into [`Digest::update`]. +pub(crate) struct HashWriter<'a, D: Digest>(pub &'a mut D); + +impl io::Write for HashWriter<'_, D> { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.0.update(buf); + Ok(buf.len()) + } + + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + /// Errors returned by [`ModelStore`] operations. #[derive(Debug, thiserror::Error)] pub enum StorageError { @@ -165,8 +186,8 @@ impl ModelStore { let mut hasher = Sha256::new(); // A full-length-partial verify always runs to completion: there is no // pause surface for it, so it never cancels. - self.feed_partial(sha256, &mut hasher, &|| false)?; - let actual = format!("{:x}", hasher.finalize()); + self.feed_partial(sha256, &mut HashWriter(&mut hasher), &|| false)?; + let actual = hex_digest(&hasher.finalize()); self.install_if_matches(sha256, &actual) } @@ -327,8 +348,20 @@ pub fn free_disk_bytes(path: &std::path::Path) -> Option { mod tests { use super::*; use sha2::{Digest, Sha256}; + use std::io::Write as _; use tempfile::TempDir; + #[test] + fn hash_writer_forwards_writes_and_flush_is_a_no_op() { + let mut hasher = Sha256::new(); + { + let mut writer = HashWriter(&mut hasher); + writer.write_all(b"abc").unwrap(); + writer.flush().unwrap(); + } + assert_eq!(hex_digest(&hasher.finalize()), sha256_of(b"abc")); + } + /// Build a fresh store rooted at a temporary directory. fn make_store() -> (TempDir, ModelStore) { let dir = TempDir::new().unwrap(); @@ -338,7 +371,7 @@ mod tests { /// Compute the hex SHA-256 of `data`. fn sha256_of(data: &[u8]) -> String { - format!("{:x}", Sha256::digest(data)) + hex_digest(&Sha256::digest(data)) } /// Write `data` into the store's partial slot for `sha256`. @@ -467,7 +500,7 @@ mod tests { // result must equal hashing the whole stream in one pass. let mut taken = store.take_suspended_hash("aa", 3).unwrap(); taken.update(b"def"); - assert_eq!(format!("{:x}", taken.finalize()), sha256_of(b"abcdef")); + assert_eq!(hex_digest(&taken.finalize()), sha256_of(b"abcdef")); } #[test]