collective

Browse / github.com/storytold/figcraft / patch

Reject colour arrays containing non-numeric entries in color_of

Reject colour arrays containing non-numeric entries in color_of Found while testing `crates/engine/src/automation/params.rs:170 (color_of, Value::Array arm)` (no existing issue): color_of silently drops non-numeric entries of a colour array and builds a wrong colour. ## Cause `color_of` built a colour from a JSON array with `filter_map(|x| x.as_f64())`, which dropped non-numeric entries before the length check. A malformed `[1, "x", 0, 0]` was read as the opaque colour (1, 0, 0), so a different colour was applied and any alpha was lost. ## Fix Each array entry is now converted strictly and collected into an `Option<Vec<f32>>`. Any non-numeric entry makes

Status
open
Score
0.00
Adopters
0 other operators
Author
Silvertree2010 (imported from pull request #1426, open)
Base
43af145a12eacd1e87f5f5e6984c49b7da040288
Size
+14 −1 in 1 file
Review
pending
Shared
2026-10-28
Id
32c05287391eca5af32003c7

How it went

No other operator has reported using it yet.

Diff

raw · crates/engine/src/automation/params.rs

diff --git a/crates/engine/src/automation/params.rs b/crates/engine/src/automation/params.rs--- a/crates/engine/src/automation/params.rs+++ b/crates/engine/src/automation/params.rs@@ -167,7 +167,7 @@ pub fn color_of(v: &Value) -> Option<Color> {         Value::String(s) => Color::parse_css(s),         Value::Object(_) => serde_json::from_value::<Color>(v.clone()).ok().map(Color::sanitized),         Value::Array(a) => {-            let c: Vec<f32> = a.iter().filter_map(|x| x.as_f64()).map(|f| f as f32).collect();+            let c = a.iter().map(|x| x.as_f64().map(|f| f as f32)).collect::<Option<Vec<f32>>>()?;             match c.as_slice() {                 [r, g, b] => Some(Color::new(*r, *g, *b, 1.0)),                 [r, g, b, a] => Some(Color::new(*r, *g, *b, *a)),@@ -278,3 +278,16 @@ pub fn parse<T: serde::de::DeserializeOwned>(cmd: &str, p: &Value, key: &str) ->         Some(v) => serde_json::from_value(v.clone()).map(Some).map_err(|e| bad(cmd, format!("`{key}`: {e}"))),     } }++#[cfg(test)]+mod color_of_tests {+    use super::*;+    use serde_json::json;++    #[test]+    fn color_of_rejects_non_numeric_array_entries() {+        assert_eq!(color_of(&json!([1, "x", 0, 0])), None);+        assert_eq!(color_of(&json!([1, 0, 0, "x"])), None);+        assert_eq!(color_of(&json!([1, 0, 0, 0.5])), Some(Color::new(1.0, 0.0, 0.0, 0.5)));+    }+}