From 54a1c81d73f0060aab97ab8ed5025f813fbe0555 Mon Sep 17 00:00:00 2001 From: iceweasel-oai Date: Wed, 4 Mar 2026 10:54:30 -0800 Subject: [PATCH] allow apps to specify cwd for sandbox setup. (#13484) The electron app doesn't start up the app-server in a particular workspace directory. So sandbox setup happens in the app-installed directory instead of the project workspace. This allows the app do specify the workspace cwd so that the sandbox setup actually sets up the ACLs instead of exiting fast and then having the first shell command be slow. --- .../schema/json/ClientRequest.json | 8 +++- .../codex_app_server_protocol.schemas.json | 8 +++- .../codex_app_server_protocol.v2.schemas.json | 8 +++- .../v2/WindowsSandboxSetupStartParams.json | 8 +++- .../v2/WindowsSandboxSetupStartParams.ts | 2 +- .../app-server-protocol/src/protocol/v2.rs | 2 + codex-rs/app-server/README.md | 2 +- .../app-server/src/codex_message_processor.rs | 38 ++++++++++++++----- .../tests/suite/v2/windows_sandbox_setup.rs | 1 + 9 files changed, 61 insertions(+), 16 deletions(-) diff --git a/codex-rs/app-server-protocol/schema/json/ClientRequest.json b/codex-rs/app-server-protocol/schema/json/ClientRequest.json index e57ffa12c..62495a79a 100644 --- a/codex-rs/app-server-protocol/schema/json/ClientRequest.json +++ b/codex-rs/app-server-protocol/schema/json/ClientRequest.json @@ -2864,6 +2864,12 @@ }, "WindowsSandboxSetupStartParams": { "properties": { + "cwd": { + "type": [ + "string", + "null" + ] + }, "mode": { "$ref": "#/definitions/WindowsSandboxSetupMode" } @@ -3908,4 +3914,4 @@ } ], "title": "ClientRequest" -} \ No newline at end of file +} diff --git a/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.schemas.json b/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.schemas.json index 2ccd20466..f09f2fc55 100644 --- a/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.schemas.json +++ b/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.schemas.json @@ -15325,6 +15325,12 @@ "WindowsSandboxSetupStartParams": { "$schema": "http://json-schema.org/draft-07/schema#", "properties": { + "cwd": { + "type": [ + "string", + "null" + ] + }, "mode": { "$ref": "#/definitions/v2/WindowsSandboxSetupMode" } @@ -15385,4 +15391,4 @@ }, "title": "CodexAppServerProtocol", "type": "object" -} \ No newline at end of file +} diff --git a/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.v2.schemas.json b/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.v2.schemas.json index 1bbea24c8..7f37aaecb 100644 --- a/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.v2.schemas.json +++ b/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.v2.schemas.json @@ -14226,6 +14226,12 @@ "WindowsSandboxSetupStartParams": { "$schema": "http://json-schema.org/draft-07/schema#", "properties": { + "cwd": { + "type": [ + "string", + "null" + ] + }, "mode": { "$ref": "#/definitions/WindowsSandboxSetupMode" } @@ -14285,4 +14291,4 @@ }, "title": "CodexAppServerProtocolV2", "type": "object" -} \ No newline at end of file +} diff --git a/codex-rs/app-server-protocol/schema/json/v2/WindowsSandboxSetupStartParams.json b/codex-rs/app-server-protocol/schema/json/v2/WindowsSandboxSetupStartParams.json index 6f0663d20..663d36064 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/WindowsSandboxSetupStartParams.json +++ b/codex-rs/app-server-protocol/schema/json/v2/WindowsSandboxSetupStartParams.json @@ -10,6 +10,12 @@ } }, "properties": { + "cwd": { + "type": [ + "string", + "null" + ] + }, "mode": { "$ref": "#/definitions/WindowsSandboxSetupMode" } @@ -19,4 +25,4 @@ ], "title": "WindowsSandboxSetupStartParams", "type": "object" -} \ No newline at end of file +} diff --git a/codex-rs/app-server-protocol/schema/typescript/v2/WindowsSandboxSetupStartParams.ts b/codex-rs/app-server-protocol/schema/typescript/v2/WindowsSandboxSetupStartParams.ts index 21daf6462..cb342c24c 100644 --- a/codex-rs/app-server-protocol/schema/typescript/v2/WindowsSandboxSetupStartParams.ts +++ b/codex-rs/app-server-protocol/schema/typescript/v2/WindowsSandboxSetupStartParams.ts @@ -3,4 +3,4 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. import type { WindowsSandboxSetupMode } from "./WindowsSandboxSetupMode"; -export type WindowsSandboxSetupStartParams = { mode: WindowsSandboxSetupMode, }; +export type WindowsSandboxSetupStartParams = { mode: WindowsSandboxSetupMode, cwd?: string | null, }; diff --git a/codex-rs/app-server-protocol/src/protocol/v2.rs b/codex-rs/app-server-protocol/src/protocol/v2.rs index 2147295c9..185d74fad 100644 --- a/codex-rs/app-server-protocol/src/protocol/v2.rs +++ b/codex-rs/app-server-protocol/src/protocol/v2.rs @@ -3927,6 +3927,8 @@ pub enum WindowsSandboxSetupMode { #[ts(export_to = "v2/")] pub struct WindowsSandboxSetupStartParams { pub mode: WindowsSandboxSetupMode, + #[ts(optional = nullable)] + pub cwd: Option, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] diff --git a/codex-rs/app-server/README.md b/codex-rs/app-server/README.md index 068d4ee18..fa1627219 100644 --- a/codex-rs/app-server/README.md +++ b/codex-rs/app-server/README.md @@ -157,7 +157,7 @@ Example with notification opt-out: - `tool/requestUserInput` — prompt the user with 1–3 short questions for a tool call and return their answers (experimental). - `config/mcpServer/reload` — reload MCP server config from disk and queue a refresh for loaded threads (applied on each thread's next active turn); returns `{}`. Use this after editing `config.toml` without restarting the server. - `mcpServerStatus/list` — enumerate configured MCP servers with their tools, resources, resource templates, and auth status; supports cursor+limit pagination. -- `windowsSandbox/setupStart` — start Windows sandbox setup for the selected mode (`elevated` or `unelevated`); returns `{ started: true }` immediately and later emits `windowsSandbox/setupCompleted`. +- `windowsSandbox/setupStart` — start Windows sandbox setup for the selected mode (`elevated` or `unelevated`); accepts an optional `cwd` to target setup for a specific workspace, returns `{ started: true }` immediately, and later emits `windowsSandbox/setupCompleted`. - `feedback/upload` — submit a feedback report (classification + optional reason/logs, conversation_id, and optional `extraLogFiles` attachments array); returns the tracking thread id. - `command/exec` — run a single command under the server sandbox without starting a thread/turn (handy for utilities and validation). - `config/read` — fetch the effective config on disk after resolving config layering. diff --git a/codex-rs/app-server/src/codex_message_processor.rs b/codex-rs/app-server/src/codex_message_processor.rs index 80558642c..8d9f08ce6 100644 --- a/codex-rs/app-server/src/codex_message_processor.rs +++ b/codex-rs/app-server/src/codex_message_processor.rs @@ -6119,21 +6119,39 @@ impl CodexMessageProcessor { WindowsSandboxSetupMode::Unelevated => CoreWindowsSandboxSetupMode::Unelevated, }; let config = Arc::clone(&self.config); + let cli_overrides = self.cli_overrides.clone(); + let cloud_requirements = self.current_cloud_requirements(); + let command_cwd = params.cwd.unwrap_or_else(|| config.cwd.clone()); let outgoing = Arc::clone(&self.outgoing); let connection_id = request_id.connection_id; tokio::spawn(async move { - let setup_request = WindowsSandboxSetupRequest { - mode, - policy: config.permissions.sandbox_policy.get().clone(), - policy_cwd: config.cwd.clone(), - command_cwd: config.cwd.clone(), - env_map: std::env::vars().collect(), - codex_home: config.codex_home.clone(), - active_profile: config.active_profile.clone(), + let derived_config = derive_config_for_cwd( + &cli_overrides, + None, + ConfigOverrides { + cwd: Some(command_cwd.clone()), + ..Default::default() + }, + Some(command_cwd.clone()), + &cloud_requirements, + ) + .await; + let setup_result = match derived_config { + Ok(config) => { + let setup_request = WindowsSandboxSetupRequest { + mode, + policy: config.permissions.sandbox_policy.get().clone(), + policy_cwd: config.cwd.clone(), + command_cwd, + env_map: std::env::vars().collect(), + codex_home: config.codex_home.clone(), + active_profile: config.active_profile.clone(), + }; + codex_core::windows_sandbox::run_windows_sandbox_setup(setup_request).await + } + Err(err) => Err(err.into()), }; - let setup_result = - codex_core::windows_sandbox::run_windows_sandbox_setup(setup_request).await; let notification = WindowsSandboxSetupCompletedNotification { mode: match mode { CoreWindowsSandboxSetupMode::Elevated => WindowsSandboxSetupMode::Elevated, diff --git a/codex-rs/app-server/tests/suite/v2/windows_sandbox_setup.rs b/codex-rs/app-server/tests/suite/v2/windows_sandbox_setup.rs index 1f069b3ca..4512d9058 100644 --- a/codex-rs/app-server/tests/suite/v2/windows_sandbox_setup.rs +++ b/codex-rs/app-server/tests/suite/v2/windows_sandbox_setup.rs @@ -37,6 +37,7 @@ async fn windows_sandbox_setup_start_emits_completion_notification() -> Result<( let request_id = mcp .send_windows_sandbox_setup_start_request(WindowsSandboxSetupStartParams { mode: WindowsSandboxSetupMode::Unelevated, + cwd: None, }) .await?; let response: JSONRPCResponse = timeout(