From 7f6c226c675535130499e8f07890f19eeb102d45 Mon Sep 17 00:00:00 2001 From: John Ky Date: Fri, 18 Sep 2026 00:26:08 +1000 Subject: [PATCH] fix(cli): avoid panic on oversized --older-than durations parse_since used the panicking chrono::Duration constructors and a plain DateTime subtraction, so an i64-valid but oversized --older-than (e.g. 100000000d or 9999999999999999w) crashed the process instead of returning the "invalid --older-than" error both `omni-dev log prune` and `omni-dev drive lease prune` already wrap around it. Switch to the checked try_* constructors and checked_sub_signed, and cover both overflow shapes (construction and subtraction) with a test. Fixes #1691 --- src/cli/log/query.rs | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/src/cli/log/query.rs b/src/cli/log/query.rs index 79986188..f45fb7b5 100644 --- a/src/cli/log/query.rs +++ b/src/cli/log/query.rs @@ -181,14 +181,17 @@ pub(crate) fn parse_since(s: &str) -> Result> { .parse() .with_context(|| format!("invalid duration: {s} (expected e.g. 30m, 2h, 1d)"))?; let dur = match unit { - "s" => Duration::seconds(n), - "m" => Duration::minutes(n), - "h" => Duration::hours(n), - "d" => Duration::days(n), - "w" => Duration::weeks(n), + "s" => Duration::try_seconds(n), + "m" => Duration::try_minutes(n), + "h" => Duration::try_hours(n), + "d" => Duration::try_days(n), + "w" => Duration::try_weeks(n), other => bail!("invalid duration unit: {other} (use s, m, h, d, or w)"), - }; - Ok(Utc::now() - dur) + } + .with_context(|| format!("invalid duration: {s} (out of range)"))?; + Utc::now() + .checked_sub_signed(dur) + .with_context(|| format!("invalid duration: {s} (out of range)")) } /// Parses an RFC3339 timestamp into UTC, or `None` if absent/unparseable. @@ -587,6 +590,12 @@ mod tests { assert!(parse_time_bound("h").is_err()); } + #[test] + fn since_rejects_oversized_duration() { + assert!(parse_since("100000000d").is_err()); // subtraction overflow + assert!(parse_since("9999999999999999w").is_err()); // construction overflow + } + #[test] fn command_prefix_matches() { let rec = LogRecord {