diff --git a/crates/automation/src/confine.rs b/crates/automation/src/confine.rs index af8a69089..b646ba7ba 100644 --- a/crates/automation/src/confine.rs +++ b/crates/automation/src/confine.rs @@ -86,13 +86,14 @@ const WRITES: &[(&str, &[&str])] = &[ ("essential.exportTemplate", &["path"]), ("shortcuts.export", &["path"]), ("renderQueue.add", &["output", "path"]), + ("file.createProxy", &["path", "output"]), ]; /// Commands that write where they are not told: the project's file, the Render Queue's outputs. const IMPLICIT_WRITES: &[&str] = &["file.save", "file.incrementAndSave", "renderQueue.render", "render.preRender"]; /// Commands that queue a render, whose output defaults to the project's folder when not given. -const QUEUES_AN_OUTPUT: &[&str] = &["renderQueue.add", "render.preRender"]; +const QUEUES_AN_OUTPUT: &[&str] = &["renderQueue.add", "render.preRender", "file.createProxy"]; /// What must be looked up before an implicitly writing command may run. #[derive(Debug, PartialEq, Eq)] diff --git a/crates/automation/src/tests.rs b/crates/automation/src/tests.rs index e3282dc71..55cc3b3cd 100644 --- a/crates/automation/src/tests.rs +++ b/crates/automation/src/tests.rs @@ -1396,7 +1396,7 @@ fn automation_roots_refuse_a_queued_output_from_an_unsaved_project() { s.backend().confine(Confinement::new(&[], std::slice::from_ref(&write)).unwrap()); call_json(&mut s, "execute_command", json!({"command": "comp.new", "params": {"name": "A", "width": 64, "height": 64}})); // Never saved: neither way of queueing a render may fall back to the home folder. - for command in ["renderQueue.add", "render.preRender"] { + for command in ["renderQueue.add", "render.preRender", "file.createProxy"] { let (c, err) = call(&mut s, "execute_command", json!({"command": command, "params": {"comp": "A"}})); assert!(err, "`{command}` without an output should be refused: {c:?}"); let msg = c[0]["text"].as_str().unwrap_or_default(); @@ -1406,6 +1406,10 @@ fn automation_roots_refuse_a_queued_output_from_an_unsaved_project() { assert_eq!(queue["items"].as_array().map(Vec::len), Some(0), "nothing was queued: {queue}"); // Naming an output inside a write root is how it is done. call_json(&mut s, "execute_command", json!({"command": "renderQueue.add", "params": {"comp": "A", "output": p("named.mp4")}})); + // A proxy's own `path` is a write, not the read it used to be checked as (#2131 F-11). + let (c, err) = call(&mut s, "execute_command", json!({"command": "file.createProxy", "params": {"comp": "A", "path": "/elsewhere/proxy.mov"}})); + assert!(err, "a proxy outside the roots should be refused: {c:?}"); + assert!(c[0]["text"].as_str().unwrap_or_default().contains("cannot write"), "{c:?}"); // Once the project is saved there, the default output (beside it) is queued as before. call_json(&mut s, "save_project", json!({"path": p("proj.ecproj")})); call_json(&mut s, "execute_command", json!({"command": "renderQueue.add", "params": {"comp": "A"}}));