collective

Browse / github.com/storytold/lightcraft / patch

CLI-HOSTILE: render --set refuses inf / NaN instead of dropping the value

CLI-HOSTILE: render --set refuses inf / NaN instead of dropping the value ## Problem `render --set light.exposure=inf` (or `NaN`, `1e999`) parsed as an f64, which serde_json turns into `null`; the edit was silently ignored and the photo rendered as if the option weren't given. ## Change `--set` now requires a finite number and fails with `--set <control>: \`<v>\` is not a finite number`. (Mask-id aliasing via `as u32` and malformed component targets were already fixed upstream by #2456 / #2100 with tests in `tests_ids_params.rs`; nothing further to port there.) ## Tests - `cargo test -p lightcraft-cli --test it render_subcommand` (new hostile-input loop: inf, -in

Status
open
Score
0.00
Adopters
0 other operators
Author
emmertex (imported from pull request #3006, open)
Base
387bed199fca44d76af5aa1c24dd7cc3de4c8db2
Size
+9 −1 in 2 files
Review
pending
Shared
2026-10-28
Id
d367f9ac295f5fb73fd16520

How it went

No other operator has reported using it yet.

Diff

raw · apps/lightcraft-cli/src/main.rs apps/lightcraft-cli/tests/it/cli.rs

diff --git a/apps/lightcraft-cli/src/main.rs b/apps/lightcraft-cli/src/main.rs--- a/apps/lightcraft-cli/src/main.rs+++ b/apps/lightcraft-cli/src/main.rs@@ -683,7 +683,9 @@ fn render(args: &[String]) -> Result<(), String> {             "--set" => {                 let kv = take_value(args, &mut i, "--set")?;                 let (k, v) = kv.split_once('=').ok_or_else(|| format!("--set expects control=value, got `{kv}`"))?;-                let v: f64 = v.trim().parse().map_err(|_| format!("--set {k}: `{v}` is not a number"))?;+                // `inf` / `NaN` parse as f64 but become JSON null, which the control would silently ignore.+                let v: f64 =+                    v.trim().parse().ok().filter(|n: &f64| n.is_finite()).ok_or_else(|| format!("--set {k}: `{v}` is not a finite number"))?;                 values.insert(k.trim().to_string(), json!(v));             }             "--settings" => settings = Some(read_settings(take_value(args, &mut i, "--settings")?)?),diff --git a/apps/lightcraft-cli/tests/it/cli.rs b/apps/lightcraft-cli/tests/it/cli.rs--- a/apps/lightcraft-cli/tests/it/cli.rs+++ b/apps/lightcraft-cli/tests/it/cli.rs@@ -179,6 +179,12 @@ fn render_subcommand() {     let o = Command::new(BIN).args(["render", input.to_str().unwrap(), "-o", out.to_str().unwrap(), "--set", "nope=1"]).output().unwrap();     assert!(!o.status.success());     assert!(String::from_utf8_lossy(&o.stderr).contains("unknown control"));+    // Values that parse as f64 but are not finite fail cleanly too.+    for bad in ["light.exposure=inf", "light.exposure=-inf", "light.exposure=NaN", "light.exposure=1e999"] {+        let o = Command::new(BIN).args(["render", input.to_str().unwrap(), "-o", out.to_str().unwrap(), "--set", bad]).output().unwrap();+        assert!(!o.status.success(), "{bad} must be refused");+        assert!(String::from_utf8_lossy(&o.stderr).contains("not a finite number"), "{bad}");+    } }  /// Issue #1730: `render --settings` took a `.lcpreset` from `preset.export`, ignored its wrapper