Control protocol docs: file.open and file.save are refused over --control (#391)

Two passages said they worked like app.open/app.save. Say what the policy
really refuses, and pin those cases in its test.
This commit is contained in:
floflo777 2026-10-07 13:05:38 +02:00 committed by GitHub
parent d91ab25772
commit 6422219226
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 12 additions and 2 deletions

View File

@ -408,7 +408,11 @@ mod tests {
#[test]
fn filesystem_commands_fail_closed() {
for id in [
"file.open",
"file.openAs",
"file.save",
"file.saveAs",
"file.saveACopy",
"file.export.saveForWebLegacy",
"pattern.import",
"layer.smartObjects.exportContents",
@ -420,6 +424,10 @@ mod tests {
assert!(authorize_engine_command(id, &serde_json::json!({})).is_err());
}
assert!(authorize_engine_command("file.new", &serde_json::json!({})).is_ok());
// The UI-level examples in docs/control-protocol.md.
for id in ["view.zoomIn", "window.theme.pro", "edit.search"] {
assert!(authorize_desktop_engine_command(id, &serde_json::json!({})).is_ok(), "{id}");
}
assert!(authorize_engine_command("image.mode.cmyk", &serde_json::json!({})).is_ok());
assert!(authorize_desktop_engine_command("image.mode.cmyk", &serde_json::json!({})).is_err());
assert!(authorize_engine_command("filter.distort.displace", &serde_json::json!({"mapPath": "outside.png"})).is_err());

View File

@ -51,7 +51,7 @@ The transport is `apps/photocraft/src/control_server.rs`, and the handlers are i
base64 PNG data; a path is relative to the automation write root. Raises the window first
(default) because occluded macOS windows stop rendering
- `ui.focus`: bring the main window to the front
- `app.open {path}` / `app.save {path}`: relative file I/O through the configured automation roots (`app.open` reads under the read root, `app.save` writes under the write root; absolute paths, `..` and paths escaping the root are refused, and both fail closed when no root was granted). Both reply with `warnings` (import/export notes such as "adjustment layer flattened"; `[]` when none), also shown to the user in the status bar and as a notice (`notices` in `ui.inspect`); `app.open` also returns the `path` and document `name`, `app.save` the `path` written. `app.save` without `path` writes back only to the document's own PSD, PSB or `.pcraft` file, like File › Save. Automation opens and saves never fire script events. `file.open`, `file.save`, `file.saveAs` and `file.saveACopy` reply with `warnings` the same way
- `app.open {path}` / `app.save {path}`: relative file I/O through the configured automation roots (`app.open` reads under the read root, `app.save` writes under the write root; absolute paths, `..` and paths escaping the root are refused, and both fail closed when no root was granted). Both reply with `warnings` (import/export notes such as "adjustment layer flattened"; `[]` when none), also shown to the user in the status bar and as a notice (`notices` in `ui.inspect`); `app.open` also returns the `path` and document `name`, `app.save` the `path` written. `app.save` without `path` writes back only to the document's own PSD, PSB or `.pcraft` file, like File › Save. Automation opens and saves never fire script events. Use these two rather than `file.open`, `file.save`, `file.saveAs` or `file.saveACopy`, which the control channel refuses (see [Engine commands](#engine-commands))
- `app.quit`
## Engine commands
@ -72,7 +72,9 @@ The transport is `apps/photocraft/src/control_server.rs`, and the handlers are i
| `document.inspect` | `{}`: layer tree, history, selection bounds |
| `document.pixel` | `{"x":10,"y":10}`: composite RGBA |
UI-level commands (`file.open`, `file.save`, `view.zoomIn`, `window.theme.pro`, `edit.search`, …) are also accepted by `engine.execute` and `ui.menu.invoke`.
UI-level commands (`view.zoomIn`, `window.theme.pro`, `edit.search`, …) are also accepted by `engine.execute` and `ui.menu.invoke`.
Commands that read or write files by path, instead of through the automation roots, are refused with "automation command `…` uses ambient filesystem paths and is disabled; use capability-scoped document methods". That covers every `file.*` command except `file.new`, the `file.close*` commands and a few path-free ones such as `file.fileInfo`, so `file.open`, `file.save`, `file.saveAs` and `file.saveACopy` always fail here: open and save with `app.open` / `app.save`. Path parameters of other commands (`layer.exportAs {path}`, `filter.distort.displace {mapPath}`, …) are refused the same way, and the desktop app also refuses `image.mode.*`, which can load the colour profiles set in its preferences. The rules are in `crates/automation/src/workspace.rs`.
### Background jobs (#210)