From d47feb00e7a817a5627ee89032ac36c50fe2440e Mon Sep 17 00:00:00 2001 From: Brett Date: Thu, 4 Jun 2026 11:30:26 -0500 Subject: [PATCH] fix(p2-json-errors): remove safe-but-flagged unwrap in is_type_id_value The `.unwrap()` on `trimmed.chars().next()` was provably safe given the prior `is_empty()` guard, but the `code-unwrap` audit pattern-matches on `.unwrap()` call expressions and reported it on self-dogfood. Replace with a `let-else` returning `false` (the function's canonical invalid-input response). One line of substance plus a comprehensive unit test covering Number/Bool/Null/Array/Object/string-shape variants. Surfaced during PR #80 review. --- src/audits/behavioral/json_errors.rs | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/src/audits/behavioral/json_errors.rs b/src/audits/behavioral/json_errors.rs index 2aaa092..66a517a 100644 --- a/src/audits/behavioral/json_errors.rs +++ b/src/audits/behavioral/json_errors.rs @@ -189,7 +189,9 @@ fn is_type_id_value(value: &Value) -> bool { { return false; } - let first = trimmed.chars().next().unwrap(); + let Some(first) = trimmed.chars().next() else { + return false; + }; if !(first.is_ascii_alphabetic() || first == '_') { return false; } @@ -311,6 +313,27 @@ mod tests { } } + #[test] + fn is_type_id_value_validates_json_shapes() { + use serde_json::json; + // Non-string values: number, bool, null, array, object — none are identifier-shaped. + assert!(!is_type_id_value(&Value::Number(42.into()))); + assert!(!is_type_id_value(&Value::Bool(true))); + assert!(!is_type_id_value(&Value::Null)); + assert!(!is_type_id_value(&json!([]))); + assert!(!is_type_id_value(&json!({}))); + // Valid identifier-shaped strings (kebab-case, SCREAMING_SNAKE, snake_case). + assert!(is_type_id_value(&Value::String("auth-required".into()))); + assert!(is_type_id_value(&Value::String("NOT_FOUND".into()))); + assert!(is_type_id_value(&Value::String("rate_limit".into()))); + // Invalid string shapes (whitespace, punctuation, leading digit). + assert!(!is_type_id_value(&Value::String("not an id".into()))); + assert!(!is_type_id_value(&Value::String("ends.with.dot".into()))); + assert!(!is_type_id_value(&Value::String( + "9starts_with_digit".into() + ))); + } + #[test] fn pass_with_all_three_keys_on_stderr() { let stderr = r#"{"error":"BadFlag","kind":"usage","message":"unknown flag --bad"}"#;