From fea84083db6bf394ab6a8feb3b215988fdcab414 Mon Sep 17 00:00:00 2001 From: Adam Poulemanos Date: Sun, 26 Jul 2026 07:51:34 -0400 Subject: [PATCH] deps: bump git2 to 0.21, clearing RUSTSEC-2026-0184 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git2 0.20.4's BlameHunk accessors build Signatures from potentially-null pointers, so reading them can dereference null (RUSTSEC-2026-0184). submod never calls blame, and the advisories step allows `unsound`, so this never failed CI — but the fix is a version bump and there is no reason to carry it. 0.21 is a breaking release. Five call sites in git2_ops.rs needed updating, all from the same API change: accessors that returned Option<&str> now return Result<&str, Error>, distinguishing "not valid UTF-8" from "absent" where the old signature collapsed both into None. Submodule::name() Option<&str> -> Result<&str, Error> Submodule::url() Option<&str> -> Result, Error> ConfigEntry::name() Option<&str> -> Result<&str, Error> ConfigEntry::value() Option<&str> -> Result<&str, Error> StatusEntry::path() Option<&str> -> Result<&str, Error> Submodule::url() is the awkward one: it grew both wrappers, since a URL can be absent *and* a present URL can be invalid UTF-8. Call sites use .ok().flatten() to fold both back to Option, preserving current behaviour rather than changing how invalid UTF-8 is handled as a side effect of a dependency bump. Submodule::name() calls needed no change: Result::unwrap_or has the same shape as Option::unwrap_or, so `.unwrap_or(path)` still compiles and still means the same thing. libgit2-sys moves 0.18.3+1.9.2 -> 0.18.7+1.9.6. 569/569 tests pass. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01XocU6NjgZricrRWMLyLXDn --- Cargo.lock | 283 +--------------------------------------- Cargo.toml | 2 +- src/git_ops/git2_ops.rs | 17 ++- 3 files changed, 15 insertions(+), 287 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index dbc38f3..e304bd1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -538,17 +538,6 @@ dependencies = [ "crypto-common", ] -[[package]] -name = "displaydoc" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ac70aa55017e108007fbaf5aa0f54b021c98f92ff8af59d42eda9da96e3dd4f" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.119", -] - [[package]] name = "document-features" version = "0.2.12" @@ -654,15 +643,6 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" -[[package]] -name = "form_urlencoded" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" -dependencies = [ - "percent-encoding", -] - [[package]] name = "futures-core" version = "0.3.33" @@ -710,17 +690,14 @@ dependencies = [ [[package]] name = "git2" -version = "0.20.4" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b88256088d75a56f8ecfa070513a775dd9107f6530ef14919dac831af9cfe2b" +checksum = "ddddbf932745a6be37109b6112d3ee09696106f848449069d3a57bba937ab82e" dependencies = [ "bitflags 2.13.1", "libc", "libgit2-sys", "log", - "openssl-probe", - "openssl-sys", - "url", ] [[package]] @@ -1746,109 +1723,6 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" -[[package]] -name = "icu_collections" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c" -dependencies = [ - "displaydoc", - "potential_utf", - "utf8_iter", - "yoke", - "zerofrom", - "zerovec", -] - -[[package]] -name = "icu_locale_core" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29" -dependencies = [ - "displaydoc", - "litemap", - "tinystr", - "writeable", - "zerovec", -] - -[[package]] -name = "icu_normalizer" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4" -dependencies = [ - "icu_collections", - "icu_normalizer_data", - "icu_properties", - "icu_provider", - "smallvec", - "zerovec", -] - -[[package]] -name = "icu_normalizer_data" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38" - -[[package]] -name = "icu_properties" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de" -dependencies = [ - "icu_collections", - "icu_locale_core", - "icu_properties_data", - "icu_provider", - "zerotrie", - "zerovec", -] - -[[package]] -name = "icu_properties_data" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14" - -[[package]] -name = "icu_provider" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421" -dependencies = [ - "displaydoc", - "icu_locale_core", - "writeable", - "yoke", - "zerofrom", - "zerotrie", - "zerovec", -] - -[[package]] -name = "idna" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" -dependencies = [ - "idna_adapter", - "smallvec", - "utf8_iter", -] - -[[package]] -name = "idna_adapter" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb68373c0d6620ef8105e855e7745e18b0d00d3bdb07fb532e434244cdb9a714" -dependencies = [ - "icu_normalizer", - "icu_properties", -] - [[package]] name = "indexmap" version = "2.14.0" @@ -2020,27 +1894,11 @@ name = "libgit2-sys" version = "0.18.7+1.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23c7391e4b9f4ffab1a624223cc1d7385ff9a678f490768add717de7ea2f4d89" -dependencies = [ - "cc", - "libc", - "libssh2-sys", - "libz-sys", - "openssl-sys", - "pkg-config", -] - -[[package]] -name = "libssh2-sys" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c04141a07bb0c0bc461cb657808764de571702a59bc5c726c400ac9a7625e3ab" dependencies = [ "cc", "libc", "libz-sys", - "openssl-sys", "pkg-config", - "vcpkg", ] [[package]] @@ -2061,12 +1919,6 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" -[[package]] -name = "litemap" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0" - [[package]] name = "litrs" version = "1.0.0" @@ -2290,15 +2142,6 @@ dependencies = [ "portable-atomic", ] -[[package]] -name = "potential_utf" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564" -dependencies = [ - "zerovec", -] - [[package]] name = "proc-macro2" version = "1.0.107" @@ -2647,17 +2490,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "synstructure" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.119", -] - [[package]] name = "tempfile" version = "3.27.0" @@ -2701,16 +2533,6 @@ dependencies = [ "syn 3.0.3", ] -[[package]] -name = "tinystr" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d" -dependencies = [ - "displaydoc", - "zerovec", -] - [[package]] name = "tinytemplate" version = "1.2.1" @@ -2834,24 +2656,6 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" -[[package]] -name = "url" -version = "2.5.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" -dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", - "serde", -] - -[[package]] -name = "utf8_iter" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" - [[package]] name = "utf8parse" version = "0.2.2" @@ -2996,35 +2800,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "writeable" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" - -[[package]] -name = "yoke" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "709fe23a0424b6a435d82152b1bd3fdfb0833487d5fa90d05d42762a9891fef5" -dependencies = [ - "stable_deref_trait", - "yoke-derive", - "zerofrom", -] - -[[package]] -name = "yoke-derive" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.119", - "synstructure", -] - [[package]] name = "zerocopy" version = "0.8.55" @@ -3045,60 +2820,6 @@ dependencies = [ "syn 2.0.119", ] -[[package]] -name = "zerofrom" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ec05a11813ea801ff6d75110ad09cd0824ddba17dfe17128ea0d5f68e6c5272" -dependencies = [ - "zerofrom-derive", -] - -[[package]] -name = "zerofrom-derive" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.119", - "synstructure", -] - -[[package]] -name = "zerotrie" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf" -dependencies = [ - "displaydoc", - "yoke", - "zerofrom", -] - -[[package]] -name = "zerovec" -version = "0.11.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239" -dependencies = [ - "yoke", - "zerofrom", - "zerovec-derive", -] - -[[package]] -name = "zerovec-derive" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.119", -] - [[package]] name = "zlib-rs" version = "0.6.6" diff --git a/Cargo.toml b/Cargo.toml index 86fb58e..09a96a0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -86,7 +86,7 @@ bitflags = "2.11.0" # As of submod v0.2.0, git2 no longer optional # gix_submodule just isn't mature enough to realistically provide our functionality without falling back to git2 -git2 = { version = "0.20.4" } +git2 = { version = "0.21.0" } [lib] name = "submod" diff --git a/src/git_ops/git2_ops.rs b/src/git_ops/git2_ops.rs index 4a802c5..42a09a6 100644 --- a/src/git_ops/git2_ops.rs +++ b/src/git_ops/git2_ops.rs @@ -40,7 +40,10 @@ impl Git2Operations { ) -> Result<(String, SubmoduleEntry)> { let name = submodule.name().unwrap_or("").to_string(); let path = submodule.path().to_string_lossy().to_string(); - let url = submodule.url().unwrap_or("").to_string(); + // git2 0.21 splits what used to be one Option: the Result is UTF-8 + // validity, the Option is whether a URL is configured at all. Both still + // collapse to "" here, matching the previous behaviour. + let url = submodule.url().ok().flatten().unwrap_or("").to_string(); // Get branch from config let branch = self.get_submodule_branch(&name)?; // Get ignore setting @@ -284,7 +287,7 @@ impl GitOperations for Git2Operations { repo_config.set_str(&format!("submodule.{name}.active"), active_str)?; } if let Some(url) = &entry.url - && submodule.url() != Some(url.as_str()) + && submodule.url().ok().flatten() != Some(url.as_str()) { repo_config.set_str(&format!("submodule.{name}.url"), url)?; } @@ -298,7 +301,7 @@ impl GitOperations for Git2Operations { let mut entries = HashMap::new(); // Iterate through config entries config.entries(None)?.for_each(|entry| { - if let (Some(name), Some(value)) = (entry.name(), entry.value()) { + if let (Ok(name), Ok(value)) = (entry.name(), entry.value()) { entries.insert(name.to_string(), value.to_string()); } })?; @@ -500,7 +503,11 @@ impl GitOperations for Git2Operations { .find_submodule(path) .with_context(|| format!("Submodule not found: {path}"))?; let name = submodule.name().unwrap_or(path).to_string(); - let url = submodule.url().map(std::string::ToString::to_string); + let url = submodule + .url() + .ok() + .flatten() + .map(std::string::ToString::to_string); // Get status let status = self @@ -612,7 +619,7 @@ impl GitOperations for Git2Operations { // Remove untracked files for entry in statuses.iter() { if entry.status().is_wt_new() - && let Some(file_path) = entry.path() + && let Ok(file_path) = entry.path() { let full_path = sub_repo .workdir()