From 6e97193b00cbe6af249336e6f4f93f8ff44d102a Mon Sep 17 00:00:00 2001 From: NetterSilver <133535268+Silvertree2010@users.noreply.github.com> Date: Fri, 16 Oct 2026 15:13:47 +0000 Subject: [PATCH] Reject impossible hour/minute/second in normalize_iso Found while testing crates/catalog/src/dates.rs:58 (normalize_iso), used by crates/engine/src/cmd/manage.rs:201 Co-Authored-By: Claude Haiku 5.5 Co-Authored-By: Claude Sonnet 5.5 Co-Authored-By: Claude Haiku 5.5 Co-Authored-By: Claude Sonnet 5.5 --- crates/catalog/src/dates.rs | 9 +++++++++ crates/catalog/src/stacks.rs | 3 +++ 2 files changed, 12 insertions(+) diff --git a/crates/catalog/src/dates.rs b/crates/catalog/src/dates.rs index 4d16c2f4d..ca463dc55 100644 --- a/crates/catalog/src/dates.rs +++ b/crates/catalog/src/dates.rs @@ -233,6 +233,15 @@ mod tests { assert_eq!(iso_seconds("2026-01-01T10:00+02:00"), iso_seconds("2026-01-01T10:00")); } + #[test] + fn impossible_times_are_rejected_not_rolled_over() { + for bad in ["2026-04-01T10:75:00", "2026-04-01 10:00:75", "2026-04-01T10:60", "2026-04-01T24:00:00", "2026-04-01T10:59:60"] { + assert_eq!(normalize_iso(bad), None, "{bad}"); + assert_eq!(shift_iso(bad, 5), None, "{bad}"); + } + assert_eq!(normalize_iso("2026-04-01T23:59:59").as_deref(), Some("2026-04-01T23:59:59")); + } + #[test] fn runs_by_day_month_year_keep_stacks_together() { let mut c = Catalog::new(); diff --git a/crates/catalog/src/stacks.rs b/crates/catalog/src/stacks.rs index eb7e89ef4..6542bfe18 100644 --- a/crates/catalog/src/stacks.rs +++ b/crates/catalog/src/stacks.rs @@ -296,6 +296,9 @@ pub fn iso_seconds(s: &str) -> Option { } let (hh, mm, ss) = if s.len() >= 16 { (num(11, 13)?, num(14, 16)?, if s.get(16..17) == Some(":") { num(17, 19).unwrap_or(0) } else { 0 }) } else { (0, 0, 0) }; + if hh >= 24 || mm >= 60 || ss >= 60 { + return None; + } // days from civil (proleptic Gregorian) let y2 = if m <= 2 { y - 1 } else { y }; let era = y2.div_euclid(400);