From 633bdb66bf2449b79055c7e3ab77ae531ee40bf9 Mon Sep 17 00:00:00 2001 From: NetterSilver <133535268+Silvertree2010@users.noreply.github.com> Date: Mon, 2 Nov 2026 05:10:06 +0100 Subject: [PATCH] Reject signed record numbers in data merge record ranges Found while testing crates/engine/src/cmd/datamerge/parse.rs:212 (parse_record_no, used by select_range) Co-Authored-By: Claude Haiku 5.5 Co-Authored-By: Claude Sonnet 5.5 --- crates/engine/src/cmd/datamerge/parse.rs | 4 ++++ crates/engine/src/cmd/datamerge/tests.rs | 8 ++++++++ 2 files changed, 12 insertions(+) diff --git a/crates/engine/src/cmd/datamerge/parse.rs b/crates/engine/src/cmd/datamerge/parse.rs index 6cc838c3c..dfc49e842 100644 --- a/crates/engine/src/cmd/datamerge/parse.rs +++ b/crates/engine/src/cmd/datamerge/parse.rs @@ -210,6 +210,10 @@ fn select_range(range: &str, count: usize, idx: &mut Vec, seen: &mut std: } fn parse_record_no(s: &str) -> Result { + // `parse` alone would accept a leading '+'. + if !s.bytes().all(|b| b.is_ascii_digit()) { + return Err(format!("bad record \"{s}\"")); + } s.parse::().map_err(|_| format!("bad record \"{s}\"")) } diff --git a/crates/engine/src/cmd/datamerge/tests.rs b/crates/engine/src/cmd/datamerge/tests.rs index 9af882653..212175d78 100644 --- a/crates/engine/src/cmd/datamerge/tests.rs +++ b/crates/engine/src/cmd/datamerge/tests.rs @@ -1179,6 +1179,14 @@ fn select_records_dedupes_large_ranges_in_first_seen_order() { assert_eq!(&idx[..3], &[4, 0, 1]); } +#[test] +fn select_records_rejects_signed_record_numbers() { + for (tok, bad) in [("+2", "+2"), ("1-+3", "+3"), ("+1,+4", "+1")] { + let err = parse::select_records(5, "range", 1, tok, None).unwrap_err(); + assert!(err.contains(&format!("bad record \"{bad}\"")), "{tok}: {err}"); + } +} + #[test] fn oversized_data_file_is_refused_before_reading() { let dir = scratch("oversized");