Keep remote workspace roots under server control (#46494)

## Why

Workspace paths from the client configuration belong to the client host. Sending them to a remote app server can override the server's workspace roots.

## What changed

- Omit client-configured `runtimeWorkspaceRoots` from remote start, resume, and fork requests so the server resolves defaults or restores saved roots.
- Preserve server-provided roots when forking an active session or side conversation, including after reloading client configuration.
- Reject `--add-dir` and `sandbox_workspace_write.writable_roots` command-line overrides with `--remote` before connecting, directing users to configure additional roots on the server.

## Testing

Add regression coverage for remote workspace roots across start, turn, resume, and fork operations; active-session forks after configuration reloads; and embedded requests retaining explicit roots. CLI tests cover rejected root overrides and continued acceptance of network-access overrides.

GitOrigin-RevId: b87ea6037d197db68e25a1a8610d693f6aa13caf
This commit is contained in:
Eric Traut
2026-09-18 22:53:00 +00:00
committed by copyberry
parent 35b746a3e3
commit 6d29cc6bac
8 changed files with 409 additions and 22 deletions
+55
View File
@@ -299,6 +299,61 @@ async fn features_list_honors_cloud_managed_feature_requirements() -> Result<()>
Ok(())
}
#[test]
fn remote_start_rejects_add_dir_before_connecting() -> Result<()> {
let home = TempDir::new()?;
let output = codex_command(home.path())?
.env("TERM", "xterm-256color")
.args(["--remote", "ws://127.0.0.1:1", "--add-dir", "remote-extra"])
.assert()
.failure()
.get_output()
.stderr
.clone();
insta::assert_snapshot!(String::from_utf8(output)?);
Ok(())
}
#[test]
fn remote_start_rejects_writable_root_overrides_before_connecting() -> Result<()> {
for config_override in [
"sandbox_workspace_write.writable_roots=[\"./extra\"]",
"sandbox_workspace_write={writable_roots=[\"./extra\"],network_access=true}",
] {
let home = TempDir::new()?;
let output = codex_command(home.path())?
.env("TERM", "xterm-256color")
.args(["--remote", "ws://127.0.0.1:1", "-c", config_override])
.assert()
.failure()
.get_output()
.stderr
.clone();
let output = String::from_utf8(output)?;
insta::allow_duplicates! {
insta::assert_snapshot!(output, @"Error: sandbox_workspace_write.writable_roots overrides are not supported with --remote. Configure additional workspace roots on the server.");
}
}
Ok(())
}
#[test]
fn remote_start_allows_network_access_overrides_before_requiring_terminal() -> Result<()> {
for config_override in [
"sandbox_workspace_write.network_access=true",
"sandbox_workspace_write={network_access=true}",
] {
let home = TempDir::new()?;
codex_command(home.path())?
.env("TERM", "xterm-256color")
.args(["--remote", "ws://127.0.0.1:1", "-c", config_override])
.assert()
.failure()
.stderr(contains("stdin is not a terminal"));
}
Ok(())
}
#[test]
fn no_daemon_rejects_agents_and_explicit_remote_targets() -> Result<()> {
for args in [
@@ -0,0 +1,5 @@
---
source: cli/tests/features.rs
expression: "String::from_utf8(output)?"
---
Error: --add-dir is not supported with --remote. Configure additional workspace roots on the server.