From 35d6e9cb61fcbe61c1eef99796e28e15bf281b57 Mon Sep 17 00:00:00 2001 From: Daniel Parks Date: Thu, 18 Jun 2026 14:57:08 -0700 Subject: [PATCH 1/2] Security: update git2 to fix undefined behavior This updates [git2] to fix two security advisories that do not seem to affect git-status-vars. ### [RUSTSEC-2026-0183] > When calling `Remote::list()` for a remote of a git repository, when > that remote does not advertise any references, git2 passes a null > pointer to the unsafe function `slice::from_raw_parts()`. Based on the > safety section documentation of function, data must be non-null even > for slices of length zero. Thus, the use of a null pointer leads to > undefined behavior. ### [RUSTSEC-2026-0184] > When a `Blame` is created via `Blame::blame_buffer()`, and a > `BlameHunk` is retrieved, the pointers to the original author, > original committer, final author, and final committer may be null if > unavailable. The corresponding `BlameHunk` methods then create > `Signature`s based on null pointers; attempting to access the data of > the `Signature`s leads to dereferencing null pointers. [git2]: https://crates.io/crates/git2 [RUSTSEC-2026-0183]: https://rustsec.org/advisories/RUSTSEC-2026-0183 [RUSTSEC-2026-0184]: https://rustsec.org/advisories/RUSTSEC-2026-0184 --- Cargo.lock | 311 +---------------------------------------------------- Cargo.toml | 2 +- src/lib.rs | 24 +++-- 3 files changed, 22 insertions(+), 315 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e2a04f0..c5625d1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -223,17 +223,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8" -[[package]] -name = "displaydoc" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "doc-comment" version = "0.3.3" @@ -269,15 +258,6 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0399f9d26e5191ce32c498bebd31e7a3ceabc2745f0ac54af3f335126c3f24b3" -[[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 = "function_name" version = "0.3.0" @@ -327,15 +307,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", "libc", "libgit2-sys", "log", - "url", ] [[package]] @@ -344,145 +323,6 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" -[[package]] -name = "icu_collections" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" -dependencies = [ - "displaydoc", - "yoke", - "zerofrom", - "zerovec", -] - -[[package]] -name = "icu_locid" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" -dependencies = [ - "displaydoc", - "litemap", - "tinystr", - "writeable", - "zerovec", -] - -[[package]] -name = "icu_locid_transform" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" -dependencies = [ - "displaydoc", - "icu_locid", - "icu_locid_transform_data", - "icu_provider", - "tinystr", - "zerovec", -] - -[[package]] -name = "icu_locid_transform_data" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7515e6d781098bf9f7205ab3fc7e9709d34554ae0b21ddbcb5febfa4bc7df11d" - -[[package]] -name = "icu_normalizer" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" -dependencies = [ - "displaydoc", - "icu_collections", - "icu_normalizer_data", - "icu_properties", - "icu_provider", - "smallvec", - "utf16_iter", - "utf8_iter", - "write16", - "zerovec", -] - -[[package]] -name = "icu_normalizer_data" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5e8338228bdc8ab83303f16b797e177953730f601a96c25d10cb3ab0daa0cb7" - -[[package]] -name = "icu_properties" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" -dependencies = [ - "displaydoc", - "icu_collections", - "icu_locid_transform", - "icu_properties_data", - "icu_provider", - "tinystr", - "zerovec", -] - -[[package]] -name = "icu_properties_data" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85fb8799753b75aee8d2a21d7c14d9f38921b54b3dbda10f5a3c7a7b82dba5e2" - -[[package]] -name = "icu_provider" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" -dependencies = [ - "displaydoc", - "icu_locid", - "icu_provider_macros", - "stable_deref_trait", - "tinystr", - "writeable", - "yoke", - "zerofrom", - "zerovec", -] - -[[package]] -name = "icu_provider_macros" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[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.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" -dependencies = [ - "icu_normalizer", - "icu_properties", -] - [[package]] name = "is_terminal_polyfill" version = "1.70.1" @@ -513,9 +353,9 @@ checksum = "58f929b4d672ea937a23a1ab494143d968337a5f47e56d0815df1e0890ddf174" [[package]] name = "libgit2-sys" -version = "0.18.3+1.9.2" +version = "0.18.5+1.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9b3acc4b91781bb0b3386669d325163746af5f6e4f73e6d2d630e09a35f3487" +checksum = "005d6ae6eac1912906073e069f7db60b1fa98e052a68227824afe3e3a1c59ca2" dependencies = [ "cc", "libc", @@ -535,12 +375,6 @@ dependencies = [ "vcpkg", ] -[[package]] -name = "litemap" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104" - [[package]] name = "log" version = "0.4.28" @@ -605,12 +439,6 @@ dependencies = [ "windows-sys 0.59.0", ] -[[package]] -name = "percent-encoding" -version = "2.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" - [[package]] name = "pin-project-lite" version = "0.2.16" @@ -745,7 +573,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" dependencies = [ "serde_core", - "serde_derive", ] [[package]] @@ -836,12 +663,6 @@ version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" -[[package]] -name = "stable_deref_trait" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" - [[package]] name = "strsim" version = "0.11.1" @@ -859,17 +680,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", -] - [[package]] name = "target-test-dir" version = "0.3.0" @@ -929,16 +739,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "tinystr" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" -dependencies = [ - "displaydoc", - "zerovec", -] - [[package]] name = "tracing" version = "0.1.41" @@ -1002,30 +802,6 @@ version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" -[[package]] -name = "url" -version = "2.5.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08bc136a29a3d1758e07a9cca267be308aeebf5cfd5a10f3f67ab2097683ef5b" -dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", - "serde", -] - -[[package]] -name = "utf16_iter" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" - -[[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" @@ -1239,87 +1015,8 @@ version = "0.45.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c573471f125075647d03df72e026074b7203790d41351cd6edc96f46bcccd36" -[[package]] -name = "write16" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" - -[[package]] -name = "writeable" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" - [[package]] name = "yansi" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" - -[[package]] -name = "yoke" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" -dependencies = [ - "serde", - "stable_deref_trait", - "yoke-derive", - "zerofrom", -] - -[[package]] -name = "yoke-derive" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "synstructure", -] - -[[package]] -name = "zerofrom" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e" -dependencies = [ - "zerofrom-derive", -] - -[[package]] -name = "zerofrom-derive" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "synstructure", -] - -[[package]] -name = "zerovec" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" -dependencies = [ - "yoke", - "zerofrom", - "zerovec-derive", -] - -[[package]] -name = "zerovec-derive" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] diff --git a/Cargo.toml b/Cargo.toml index b4cf1ae..00df817 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,7 +16,7 @@ rust-version = "1.74.1" [dependencies] clap = { version = "4.5.23", features = ["derive"] } duration-str = { version = "0.17.0", default-features = false, features = ["lowercase", "no_calc"] } -git2 = { version = "0.20.4", default-features = false } +git2 = { version = "0.21.0", default-features = false } libc = "0.2.174" nix = { version = "0.30.1", features = ["signal", "process"] } shell-words = "1.1.0" diff --git a/src/lib.rs b/src/lib.rs index c08d219..ec6db43 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -271,24 +271,34 @@ pub fn head_info(repository: &Repository) -> Head { match repository.find_reference(¤t) { Ok(reference) => match reference.kind() { Some(ReferenceType::Direct) => { - head.trail.push(Reference::direct(display_option( - reference.name(), - ))); + head.trail.push(Reference::direct( + reference + .name() + .expect("getting reference name") + .to_owned(), + )); head.hash = display_option(reference.target()); break; } Some(ReferenceType::Symbolic) => { - head.trail.push(Reference::symbolic(display_option( - reference.name(), - ))); + head.trail.push(Reference::symbolic( + reference + .name() + .expect("getting reference name") + .to_owned(), + )); let target = reference .symbolic_target() + .expect("getting symbolic target") .expect("Symbolic ref should have symbolic target"); target.clone_into(&mut current); } None => { head.trail.push(Reference::new( - display_option(reference.name()), + reference + .name() + .expect("getting reference name") + .to_owned(), "unknown", )); break; From 058e5ca710c69e36ae1e2c3bdb93ed7566c64c6e Mon Sep 17 00:00:00 2001 From: Daniel Parks Date: Thu, 18 Jun 2026 15:22:25 -0700 Subject: [PATCH 2/2] Bump MSRV to 1.87 for git2 Bump edition to 2024 at the same time, and fix a bunch of lints. --- CHANGELOG.md | 9 +++++++++ Cargo.toml | 4 ++-- README.md | 2 +- src/lib.rs | 11 ++++++----- src/main.rs | 2 +- src/params.rs | 2 +- src/unix.rs | 4 ++-- tests/helpers/mod.rs | 7 +++++-- tests/meta.rs | 3 +-- 9 files changed, 28 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4a5c1ac..2b67706 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,16 @@ All notable changes to this project will be documented in this file. * Enable [“fat” link time optimization][lto] for release builds. On macOS, the resulting binary went from 1.3 MB to 1.0 MB. +### Security fixes + +* Updated [git2] version to avoid two vulnerabilities ([RUSTSEC-2026-0183] and + [RUSTSEC-2026-0184]) that likely do not affect git-status-vars. This required + bumping the MSRV to 1.87, so I also updated to Rust edition 2024. + [lto]: https://doc.rust-lang.org/rustc/codegen-options/index.html#lto +[git2]: https://crates.io/crates/git2 +[RUSTSEC-2026-0183]: https://rustsec.org/advisories/RUSTSEC-2026-0183 +[RUSTSEC-2026-0184]: https://rustsec.org/advisories/RUSTSEC-2026-0184 ## Release 1.3.0 (2025-10-16) diff --git a/Cargo.toml b/Cargo.toml index 00df817..2fa6de3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,8 +10,8 @@ readme = "README.md" keywords = ["git", "shell", "prompt", "zsh", "bash"] categories = ["development-tools", "command-line-utilities"] license = "MIT OR Apache-2.0" -edition = "2021" -rust-version = "1.74.1" +edition = "2024" +rust-version = "1.87" [dependencies] clap = { version = "4.5.23", features = ["derive"] } diff --git a/README.md b/README.md index dbecb9b..889f715 100644 --- a/README.md +++ b/README.md @@ -160,7 +160,7 @@ I have not tested this on large repositories. I’m not sure how useful it is, but this may be used from other Rust code. -Currently the minimum supported Rust version (MSRV) is **1.74.1**. +Currently the minimum supported Rust version (MSRV) is **1.87**. ## Development and contributions diff --git a/src/lib.rs b/src/lib.rs index ec6db43..3213c09 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,7 +4,7 @@ //! The primary entrance to this code is [`summarize_repository()`]. It opens a //! [`Repository`], then calls [`summarize_opened_repository()`] on it. //! -//! Currently the minimum supported Rust version (MSRV) is **1.74.1**. +//! Currently the minimum supported Rust version (MSRV) is **1.87**. //! //! # Versioning //! @@ -137,8 +137,10 @@ impl ShellVars for Head { let trail = self.trail.get(1..).unwrap_or(&[]); out.write_var("ref_length", trail.len()); for (i, reference) in trail.iter().enumerate() { - // self.trail is actually 1 longer, so i + 1 always fits. - #[allow(clippy::arithmetic_side_effects)] + #[expect( + clippy::arithmetic_side_effects, + reason = "self.trail is actually 1 longer, so i + 1 always fits" + )] out.group_n("ref", i + 1).write_vars(reference); } out.write_var("hash", &self.hash); @@ -262,7 +264,6 @@ pub fn summarize_opened_repository( /// /// This may panic if it can’t resolve a symbolic reference to a symbolic /// target. -#[allow(clippy::similar_names)] #[must_use] pub fn head_info(repository: &Repository) -> Head { let mut current = "HEAD".to_owned(); @@ -309,7 +310,7 @@ pub fn head_info(repository: &Repository) -> Head { .push(Reference::new_with_error(current, "", error)); break; } - }; + } } match get_upstream_difference(repository) { diff --git a/src/main.rs b/src/main.rs index 3dfd493..7accab9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,8 +1,8 @@ //! git-status-vars executable. use clap::Parser; +use git_status_vars::{ShellWriter, summarize_repository}; use git2::Repository; -use git_status_vars::{summarize_repository, ShellWriter}; use std::io; mod params; diff --git a/src/params.rs b/src/params.rs index 90be36d..e479f63 100644 --- a/src/params.rs +++ b/src/params.rs @@ -41,8 +41,8 @@ pub struct Params { /// Parse a duration from a parameter. #[cfg(not(windows))] fn parse_duration(input: &str) -> Result { - use clap::error::ErrorKind; use clap::CommandFactory; + use clap::error::ErrorKind; let input = input.trim(); diff --git a/src/unix.rs b/src/unix.rs index 79cd3af..58b1528 100644 --- a/src/unix.rs +++ b/src/unix.rs @@ -3,9 +3,9 @@ //! This is part of the executable, not the library; `unsafe` is allowed. use nix::sys::signal::{ - kill, sigaction, SaFlags, SigAction, SigHandler, SigSet, Signal, + SaFlags, SigAction, SigHandler, SigSet, Signal, kill, sigaction, }; -use nix::unistd::{fork, getpid, write, ForkResult, Pid}; +use nix::unistd::{ForkResult, Pid, fork, getpid, write}; use std::thread; use std::time::Duration; diff --git a/tests/helpers/mod.rs b/tests/helpers/mod.rs index 7a3133d..017a040 100644 --- a/tests/helpers/mod.rs +++ b/tests/helpers/mod.rs @@ -169,8 +169,11 @@ pub fn strip_indent(input: &str) -> String { .strip_prefix('\n') .map(|rest| rest.trim_start_matches(' ')) // Strip first indent. .map(|rest| { - // Get the length of the "\n "-like prefix. (This is always safe.) - #[allow(clippy::arithmetic_side_effects)] + // Get the length of the "\n "-like prefix. + #[expect( + clippy::arithmetic_side_effects, + reason = "rest always shorter than input" + )] let prefix_len = input.len() - rest.len(); if prefix_len > 1 { // There was an indent. Replace all newline plus indent diff --git a/tests/meta.rs b/tests/meta.rs index 45aeff1..cbc5e5a 100644 --- a/tests/meta.rs +++ b/tests/meta.rs @@ -1,7 +1,6 @@ //! Test the test helpers. -// We don’t use everything in helpers. -#[allow(dead_code)] +#[expect(dead_code, reason = "helpers has code to support other modules")] mod helpers; #[test]