From 3ac1d155987b40a2a4564428b44460f8fe746473 Mon Sep 17 00:00:00 2001 From: pakrym-oai Date: Wed, 13 May 2026 13:18:56 -0700 Subject: [PATCH] Use selected environment cwd for filesystem helpers (#22542) ## Why `TurnContext::cwd` is deprecated in favor of resolving paths from the selected turn environment cwd. A few filesystem-oriented paths were still constructing sandbox context from the legacy cwd and then mutating it afterward, or resolving local file paths through the deprecated helper. ## What changed - Make `TurnContext::file_system_sandbox_context` take the trusted cwd explicitly. - Pass the selected turn environment cwd directly from `apply_patch` and `view_image` call sites. - Restrict `spawn_agents_on_csv` to exactly one local environment and resolve input/output CSV paths from that local environment cwd. - Remove a redundant test setup assignment that only synchronized deprecated `TurnContext::cwd` with a replaced config. ## Validation - `cargo test -p codex-core view_image` - `cargo test -p codex-core maybe_persist_mcp_tool_approval_writes_project_config_for_project_server` - `cargo test -p codex-core parse_csv_supports_quotes_and_commas` - `git diff --check` --- codex-rs/core/src/mcp_tool_call_tests.rs | 4 --- codex-rs/core/src/session/turn_context.rs | 4 +-- .../agent_jobs/spawn_agents_on_csv.rs | 26 ++++++++++++++----- .../core/src/tools/handlers/apply_patch.rs | 6 ++--- .../core/src/tools/handlers/view_image.rs | 8 ++---- 5 files changed, 26 insertions(+), 22 deletions(-) diff --git a/codex-rs/core/src/mcp_tool_call_tests.rs b/codex-rs/core/src/mcp_tool_call_tests.rs index 8b4f1ba223..714b0b99e6 100644 --- a/codex-rs/core/src/mcp_tool_call_tests.rs +++ b/codex-rs/core/src/mcp_tool_call_tests.rs @@ -2233,10 +2233,6 @@ async fn maybe_persist_mcp_tool_approval_writes_project_config_for_project_serve .build() .await .expect("load project config"); - #[allow(deprecated)] - { - turn_context.cwd = config.cwd.clone(); - } turn_context.config = Arc::new(config); let key = McpToolApprovalKey { server: "docs".to_string(), diff --git a/codex-rs/core/src/session/turn_context.rs b/codex-rs/core/src/session/turn_context.rs index 8caec7aaea..71e238a540 100644 --- a/codex-rs/core/src/session/turn_context.rs +++ b/codex-rs/core/src/session/turn_context.rs @@ -301,6 +301,7 @@ impl TurnContext { pub(crate) fn file_system_sandbox_context( &self, additional_permissions: Option, + cwd: &AbsolutePathBuf, ) -> FileSystemSandboxContext { let (base_file_system_sandbox_policy, base_network_sandbox_policy) = self.permission_profile.to_runtime_permissions(); @@ -319,8 +320,7 @@ impl TurnContext { ); FileSystemSandboxContext { permissions, - #[allow(deprecated)] - cwd: Some(self.cwd.clone()), + cwd: Some(cwd.clone()), windows_sandbox_level: self.windows_sandbox_level, windows_sandbox_private_desktop: self .config diff --git a/codex-rs/core/src/tools/handlers/agent_jobs/spawn_agents_on_csv.rs b/codex-rs/core/src/tools/handlers/agent_jobs/spawn_agents_on_csv.rs index e1a37be6b6..6ad0515e81 100644 --- a/codex-rs/core/src/tools/handlers/agent_jobs/spawn_agents_on_csv.rs +++ b/codex-rs/core/src/tools/handlers/agent_jobs/spawn_agents_on_csv.rs @@ -7,6 +7,7 @@ use crate::tools::registry::ToolExecutor; use crate::tools::registry::ToolHandler; use codex_tools::ToolName; use codex_tools::ToolSpec; +use codex_utils_absolute_path::AbsolutePathBuf; use super::*; @@ -67,9 +68,9 @@ pub async fn handle( )); } + let cwd = single_local_environment_cwd(&turn)?; let db = required_state_db(&session)?; - #[allow(deprecated)] - let input_path = turn.resolve_path(Some(args.csv_path)); + let input_path = cwd.join(args.csv_path); let input_path_display = input_path.display().to_string(); let csv_content = tokio::fs::read_to_string(&input_path) .await @@ -142,10 +143,7 @@ pub async fn handle( let job_id = Uuid::new_v4().to_string(); let output_csv_path = args.output_csv_path.map_or_else( || default_output_csv_path(&input_path, job_id.as_str()), - |path| { - #[allow(deprecated)] - turn.resolve_path(Some(path)) - }, + |path| cwd.join(path), ); let job_suffix = &job_id[..8]; let job_name = format!("agent-job-{job_suffix}"); @@ -290,3 +288,19 @@ pub async fn handle( })?; Ok(FunctionToolOutput::from_text(content, Some(true))) } + +fn single_local_environment_cwd(turn: &TurnContext) -> Result<&AbsolutePathBuf, FunctionCallError> { + let [turn_environment] = turn.environments.turn_environments.as_slice() else { + return Err(FunctionCallError::RespondToModel( + "spawn_agents_on_csv requires exactly one local environment".to_string(), + )); + }; + + if turn_environment.environment.is_remote() { + return Err(FunctionCallError::RespondToModel( + "spawn_agents_on_csv is not supported for remote environments".to_string(), + )); + } + + Ok(&turn_environment.cwd) +} diff --git a/codex-rs/core/src/tools/handlers/apply_patch.rs b/codex-rs/core/src/tools/handlers/apply_patch.rs index 32edd21da1..5a709b287f 100644 --- a/codex-rs/core/src/tools/handlers/apply_patch.rs +++ b/codex-rs/core/src/tools/handlers/apply_patch.rs @@ -345,8 +345,7 @@ impl ToolExecutor for ApplyPatchHandler { }; let cwd = turn_environment.cwd.clone(); let fs = turn_environment.environment.get_filesystem(); - let mut sandbox = turn.file_system_sandbox_context(/*additional_permissions*/ None); - sandbox.cwd = Some(cwd.clone()); + let sandbox = turn.file_system_sandbox_context(/*additional_permissions*/ None, &cwd); match codex_apply_patch::verify_apply_patch_args(args, &cwd, fs.as_ref(), Some(&sandbox)) .await { @@ -499,8 +498,7 @@ pub(crate) async fn intercept_apply_patch( call_id: &str, tool_name: &str, ) -> Result, FunctionCallError> { - let mut sandbox = turn.file_system_sandbox_context(/*additional_permissions*/ None); - sandbox.cwd = Some(cwd.clone()); + let sandbox = turn.file_system_sandbox_context(/*additional_permissions*/ None, cwd); match codex_apply_patch::maybe_parse_apply_patch_verified(command, cwd, fs, Some(&sandbox)) .await { diff --git a/codex-rs/core/src/tools/handlers/view_image.rs b/codex-rs/core/src/tools/handlers/view_image.rs index bb74adb86d..1587e90ddb 100644 --- a/codex-rs/core/src/tools/handlers/view_image.rs +++ b/codex-rs/core/src/tools/handlers/view_image.rs @@ -134,8 +134,7 @@ impl ToolExecutor for ViewImageHandler { }; let cwd = turn_environment.cwd.clone(); let abs_path = cwd.join(path); - let mut sandbox = turn.file_system_sandbox_context(/*additional_permissions*/ None); - sandbox.cwd = Some(cwd.clone()); + let sandbox = turn.file_system_sandbox_context(/*additional_permissions*/ None, &cwd); let fs = turn_environment.environment.get_filesystem(); let metadata = fs @@ -282,10 +281,7 @@ mod tests { let (session, mut turn) = make_session_and_context().await; let image_dir = tempfile::tempdir().expect("create image temp dir"); let image_cwd = image_dir.abs(); - #[allow(deprecated)] - { - turn.cwd = image_cwd.clone(); - } + turn.environments .turn_environments .first_mut()