From 52e79ee49a238ea8bfeb1698418deb000bab4e7e Mon Sep 17 00:00:00 2001 From: Michael Bolin Date: Tue, 28 Apr 2026 17:05:53 -0700 Subject: [PATCH 1/2] core tests: migrate more turns to permission profiles (#20013) ## Summary - Migrate another batch of direct `Op::UserTurn` test construction from legacy `SandboxPolicy` values to `PermissionProfile` inputs via `turn_permission_fields()`. - Replace a one-off read-only `SandboxPolicy` bridge in the macOS exec test with `PermissionProfile::read_only()`. - Reduce `SandboxPolicy` references in `codex-rs/core/tests` from 32 files at the start of the cleanup stack to 27 files. ## Testing - `cargo check -p codex-core --tests` - `just fmt` - `just fix -p codex-core` --- codex-rs/core/tests/suite/exec.rs | 6 +-- .../core/tests/suite/models_etag_responses.rs | 12 +++-- codex-rs/core/tests/suite/shell_snapshot.rs | 27 +++++++---- codex-rs/core/tests/suite/sqlite_state.rs | 12 +++-- codex-rs/core/tests/suite/tool_harness.rs | 48 ++++++++++++------- 5 files changed, 67 insertions(+), 38 deletions(-) diff --git a/codex-rs/core/tests/suite/exec.rs b/codex-rs/core/tests/suite/exec.rs index a0dd7f8e25..923d223e13 100644 --- a/codex-rs/core/tests/suite/exec.rs +++ b/codex-rs/core/tests/suite/exec.rs @@ -9,7 +9,6 @@ use codex_protocol::config_types::WindowsSandboxLevel; use codex_protocol::error::Result; use codex_protocol::exec_output::ExecToolCallOutput; use codex_protocol::models::PermissionProfile; -use codex_protocol::protocol::SandboxPolicy; use codex_sandboxing::SandboxType; use codex_sandboxing::get_platform_sandbox; use core_test_support::PathExt; @@ -50,12 +49,9 @@ where arg0: None, }; - let policy = SandboxPolicy::new_read_only_policy(); - let permission_profile = PermissionProfile::from_legacy_sandbox_policy(&policy); - process_exec_tool_call( params, - &permission_profile, + &PermissionProfile::read_only(), &cwd, &None, /*use_legacy_landlock*/ false, diff --git a/codex-rs/core/tests/suite/models_etag_responses.rs b/codex-rs/core/tests/suite/models_etag_responses.rs index 0551dcf8e1..a9aa843ad1 100644 --- a/codex-rs/core/tests/suite/models_etag_responses.rs +++ b/codex-rs/core/tests/suite/models_etag_responses.rs @@ -6,11 +6,11 @@ use std::time::Duration; use anyhow::Result; use codex_features::Feature; use codex_login::CodexAuth; +use codex_protocol::models::PermissionProfile; use codex_protocol::openai_models::ModelsResponse; use codex_protocol::protocol::AskForApproval; use codex_protocol::protocol::EventMsg; use codex_protocol::protocol::Op; -use codex_protocol::protocol::SandboxPolicy; use codex_protocol::user_input::UserInput; use core_test_support::responses; use core_test_support::responses::ev_assistant_message; @@ -21,6 +21,7 @@ use core_test_support::responses::sse; use core_test_support::responses::sse_response; use core_test_support::skip_if_no_network; use core_test_support::test_codex::test_codex; +use core_test_support::test_codex::turn_permission_fields; use core_test_support::wait_for_event_with_timeout; use pretty_assertions::assert_eq; use wiremock::MockServer; @@ -61,6 +62,9 @@ async fn refresh_models_on_models_etag_mismatch_and_avoid_duplicate_models_fetch let codex = Arc::clone(&test.codex); let cwd = Arc::clone(&test.cwd); let session_model = test.session_configured.model.clone(); + let cwd_path = cwd.path().to_path_buf(); + let (sandbox_policy, permission_profile) = + turn_permission_fields(PermissionProfile::Disabled, cwd_path.as_path()); assert_eq!(spawn_models_mock.requests().len(), 1); assert_eq!(spawn_models_mock.single_request_path(), "/v1/models"); @@ -107,11 +111,11 @@ async fn refresh_models_on_models_etag_mismatch_and_avoid_duplicate_models_fetch text_elements: Vec::new(), }], final_output_json_schema: None, - cwd: cwd.path().to_path_buf(), + cwd: cwd_path, approval_policy: AskForApproval::Never, approvals_reviewer: None, - sandbox_policy: SandboxPolicy::DangerFullAccess, - permission_profile: None, + sandbox_policy, + permission_profile, model: session_model, effort: None, summary: None, diff --git a/codex-rs/core/tests/suite/shell_snapshot.rs b/codex-rs/core/tests/suite/shell_snapshot.rs index 1204f2b078..f757fa322a 100644 --- a/codex-rs/core/tests/suite/shell_snapshot.rs +++ b/codex-rs/core/tests/suite/shell_snapshot.rs @@ -1,11 +1,11 @@ use anyhow::Result; use codex_features::Feature; +use codex_protocol::models::PermissionProfile; use codex_protocol::protocol::AskForApproval; use codex_protocol::protocol::EventMsg; use codex_protocol::protocol::ExecCommandBeginEvent; use codex_protocol::protocol::ExecCommandEndEvent; use codex_protocol::protocol::Op; -use codex_protocol::protocol::SandboxPolicy; use codex_protocol::user_input::UserInput; use core_test_support::responses::ev_assistant_message; use core_test_support::responses::ev_completed; @@ -15,6 +15,7 @@ use core_test_support::responses::mount_sse_sequence; use core_test_support::responses::sse; use core_test_support::test_codex::TestCodexHarness; use core_test_support::test_codex::test_codex; +use core_test_support::test_codex::turn_permission_fields; use core_test_support::wait_for_event; use core_test_support::wait_for_event_match; use pretty_assertions::assert_eq; @@ -154,6 +155,8 @@ async fn run_snapshot_command_with_options( let codex_home = test.home.path().to_path_buf(); let session_model = test.session_configured.model.clone(); let cwd = test.cwd_path().to_path_buf(); + let (sandbox_policy, permission_profile) = + turn_permission_fields(PermissionProfile::Disabled, cwd.as_path()); codex .submit(Op::UserTurn { @@ -166,8 +169,8 @@ async fn run_snapshot_command_with_options( cwd, approval_policy: AskForApproval::Never, approvals_reviewer: None, - sandbox_policy: SandboxPolicy::DangerFullAccess, - permission_profile: None, + sandbox_policy, + permission_profile, model: session_model, effort: None, summary: None, @@ -247,6 +250,8 @@ async fn run_shell_command_snapshot_with_options( let codex_home = test.home.path().to_path_buf(); let session_model = test.session_configured.model.clone(); let cwd = test.cwd_path().to_path_buf(); + let (sandbox_policy, permission_profile) = + turn_permission_fields(PermissionProfile::Disabled, cwd.as_path()); codex .submit(Op::UserTurn { @@ -259,8 +264,8 @@ async fn run_shell_command_snapshot_with_options( cwd, approval_policy: AskForApproval::Never, approvals_reviewer: None, - sandbox_policy: SandboxPolicy::DangerFullAccess, - permission_profile: None, + sandbox_policy, + permission_profile, model: session_model, effort: None, summary: None, @@ -321,6 +326,8 @@ async fn run_tool_turn_on_harness( let codex = test.codex.clone(); let session_model = test.session_configured.model.clone(); let cwd = test.cwd_path().to_path_buf(); + let (sandbox_policy, permission_profile) = + turn_permission_fields(PermissionProfile::Disabled, cwd.as_path()); codex .submit(Op::UserTurn { environments: None, @@ -332,8 +339,8 @@ async fn run_tool_turn_on_harness( cwd, approval_policy: AskForApproval::Never, approvals_reviewer: None, - sandbox_policy: SandboxPolicy::DangerFullAccess, - permission_profile: None, + sandbox_policy, + permission_profile, model: session_model, effort: None, summary: None, @@ -558,6 +565,8 @@ async fn shell_command_snapshot_still_intercepts_apply_patch() -> Result<()> { mount_sse_sequence(harness.server(), responses).await; let model = test.session_configured.model.clone(); + let (sandbox_policy, permission_profile) = + turn_permission_fields(PermissionProfile::Disabled, cwd.as_path()); codex .submit(Op::UserTurn { environments: None, @@ -569,8 +578,8 @@ async fn shell_command_snapshot_still_intercepts_apply_patch() -> Result<()> { cwd: cwd.clone(), approval_policy: AskForApproval::Never, approvals_reviewer: None, - sandbox_policy: SandboxPolicy::DangerFullAccess, - permission_profile: None, + sandbox_policy, + permission_profile, model, effort: None, summary: None, diff --git a/codex-rs/core/tests/suite/sqlite_state.rs b/codex-rs/core/tests/suite/sqlite_state.rs index 8ad9ede5b9..8250f5493d 100644 --- a/codex-rs/core/tests/suite/sqlite_state.rs +++ b/codex-rs/core/tests/suite/sqlite_state.rs @@ -4,12 +4,12 @@ use codex_config::types::McpServerTransportConfig; use codex_features::Feature; use codex_protocol::ThreadId; use codex_protocol::dynamic_tools::DynamicToolSpec; +use codex_protocol::models::PermissionProfile; use codex_protocol::protocol::AskForApproval; use codex_protocol::protocol::EventMsg; use codex_protocol::protocol::Op; use codex_protocol::protocol::RolloutItem; use codex_protocol::protocol::RolloutLine; -use codex_protocol::protocol::SandboxPolicy; use codex_protocol::protocol::SessionMeta; use codex_protocol::protocol::SessionMetaLine; use codex_protocol::protocol::SessionSource; @@ -26,6 +26,7 @@ use core_test_support::responses::start_mock_server; use core_test_support::skip_if_no_network; use core_test_support::stdio_server_bin; use core_test_support::test_codex::test_codex; +use core_test_support::test_codex::turn_permission_fields; use core_test_support::wait_for_event; use core_test_support::wait_for_event_match; use pretty_assertions::assert_eq; @@ -396,6 +397,9 @@ async fn mcp_call_marks_thread_memory_mode_polluted_when_configured() -> Result< let test = builder.build(&server).await?; let db = test.codex.state_db().expect("state db enabled"); let thread_id = test.session_configured.session_id; + let cwd = test.cwd_path().to_path_buf(); + let (sandbox_policy, permission_profile) = + turn_permission_fields(PermissionProfile::read_only(), cwd.as_path()); test.codex .submit(Op::UserTurn { @@ -405,11 +409,11 @@ async fn mcp_call_marks_thread_memory_mode_polluted_when_configured() -> Result< text_elements: Vec::new(), }], final_output_json_schema: None, - cwd: test.cwd_path().to_path_buf(), + cwd, approval_policy: AskForApproval::Never, approvals_reviewer: None, - sandbox_policy: SandboxPolicy::new_read_only_policy(), - permission_profile: None, + sandbox_policy, + permission_profile, model: test.session_configured.model.clone(), effort: None, summary: None, diff --git a/codex-rs/core/tests/suite/tool_harness.rs b/codex-rs/core/tests/suite/tool_harness.rs index db93c0b66e..62d6dcef90 100644 --- a/codex-rs/core/tests/suite/tool_harness.rs +++ b/codex-rs/core/tests/suite/tool_harness.rs @@ -4,11 +4,11 @@ use std::fs; use assert_matches::assert_matches; use codex_features::Feature; +use codex_protocol::models::PermissionProfile; use codex_protocol::plan_tool::StepStatus; use codex_protocol::protocol::AskForApproval; use codex_protocol::protocol::EventMsg; use codex_protocol::protocol::Op; -use codex_protocol::protocol::SandboxPolicy; use codex_protocol::user_input::UserInput; use core_test_support::assert_regex_match; use core_test_support::responses; @@ -24,6 +24,7 @@ use core_test_support::responses::start_mock_server; use core_test_support::skip_if_no_network; use core_test_support::test_codex::TestCodex; use core_test_support::test_codex::test_codex; +use core_test_support::test_codex::turn_permission_fields; use core_test_support::wait_for_event; use serde_json::Value; use serde_json::json; @@ -75,6 +76,9 @@ async fn shell_tool_executes_command_and_streams_output() -> anyhow::Result<()> let second_mock = responses::mount_sse_once(&server, second_response).await; let session_model = session_configured.model.clone(); + let cwd_path = cwd.path().to_path_buf(); + let (sandbox_policy, permission_profile) = + turn_permission_fields(PermissionProfile::Disabled, cwd_path.as_path()); codex .submit(Op::UserTurn { @@ -84,11 +88,11 @@ async fn shell_tool_executes_command_and_streams_output() -> anyhow::Result<()> text_elements: Vec::new(), }], final_output_json_schema: None, - cwd: cwd.path().to_path_buf(), + cwd: cwd_path, approval_policy: AskForApproval::Never, approvals_reviewer: None, - sandbox_policy: SandboxPolicy::DangerFullAccess, - permission_profile: None, + sandbox_policy, + permission_profile, model: session_model, effort: None, summary: None, @@ -148,6 +152,9 @@ async fn update_plan_tool_emits_plan_update_event() -> anyhow::Result<()> { let second_mock = responses::mount_sse_once(&server, second_response).await; let session_model = session_configured.model.clone(); + let cwd_path = cwd.path().to_path_buf(); + let (sandbox_policy, permission_profile) = + turn_permission_fields(PermissionProfile::Disabled, cwd_path.as_path()); codex .submit(Op::UserTurn { @@ -157,11 +164,11 @@ async fn update_plan_tool_emits_plan_update_event() -> anyhow::Result<()> { text_elements: Vec::new(), }], final_output_json_schema: None, - cwd: cwd.path().to_path_buf(), + cwd: cwd_path, approval_policy: AskForApproval::Never, approvals_reviewer: None, - sandbox_policy: SandboxPolicy::DangerFullAccess, - permission_profile: None, + sandbox_policy, + permission_profile, model: session_model, effort: None, summary: None, @@ -231,6 +238,9 @@ async fn update_plan_tool_rejects_malformed_payload() -> anyhow::Result<()> { let second_mock = responses::mount_sse_once(&server, second_response).await; let session_model = session_configured.model.clone(); + let cwd_path = cwd.path().to_path_buf(); + let (sandbox_policy, permission_profile) = + turn_permission_fields(PermissionProfile::Disabled, cwd_path.as_path()); codex .submit(Op::UserTurn { @@ -240,11 +250,11 @@ async fn update_plan_tool_rejects_malformed_payload() -> anyhow::Result<()> { text_elements: Vec::new(), }], final_output_json_schema: None, - cwd: cwd.path().to_path_buf(), + cwd: cwd_path, approval_policy: AskForApproval::Never, approvals_reviewer: None, - sandbox_policy: SandboxPolicy::DangerFullAccess, - permission_profile: None, + sandbox_policy, + permission_profile, model: session_model, effort: None, summary: None, @@ -329,6 +339,9 @@ async fn apply_patch_tool_executes_and_emits_patch_events() -> anyhow::Result<() let second_mock = responses::mount_sse_once(&server, second_response).await; let session_model = session_configured.model.clone(); + let cwd_path = cwd.path().to_path_buf(); + let (sandbox_policy, permission_profile) = + turn_permission_fields(PermissionProfile::Disabled, cwd_path.as_path()); codex .submit(Op::UserTurn { @@ -338,11 +351,11 @@ async fn apply_patch_tool_executes_and_emits_patch_events() -> anyhow::Result<() text_elements: Vec::new(), }], final_output_json_schema: None, - cwd: cwd.path().to_path_buf(), + cwd: cwd_path, approval_policy: AskForApproval::Never, approvals_reviewer: None, - sandbox_policy: SandboxPolicy::DangerFullAccess, - permission_profile: None, + sandbox_policy, + permission_profile, model: session_model, effort: None, summary: None, @@ -435,6 +448,9 @@ async fn apply_patch_reports_parse_diagnostics() -> anyhow::Result<()> { let second_mock = responses::mount_sse_once(&server, second_response).await; let session_model = session_configured.model.clone(); + let cwd_path = cwd.path().to_path_buf(); + let (sandbox_policy, permission_profile) = + turn_permission_fields(PermissionProfile::Disabled, cwd_path.as_path()); codex .submit(Op::UserTurn { @@ -444,11 +460,11 @@ async fn apply_patch_reports_parse_diagnostics() -> anyhow::Result<()> { text_elements: Vec::new(), }], final_output_json_schema: None, - cwd: cwd.path().to_path_buf(), + cwd: cwd_path, approval_policy: AskForApproval::Never, approvals_reviewer: None, - sandbox_policy: SandboxPolicy::DangerFullAccess, - permission_profile: None, + sandbox_policy, + permission_profile, model: session_model, effort: None, summary: None, From dc8896930ff35fdf13b7b4c5659cfe08921e2ce7 Mon Sep 17 00:00:00 2001 From: Michael Bolin Date: Tue, 28 Apr 2026 17:06:06 -0700 Subject: [PATCH 2/2] core tests: configure profiles directly --- codex-rs/core/tests/suite/code_mode.rs | 13 ++++-- codex-rs/core/tests/suite/codex_delegate.rs | 12 +++--- .../core/tests/suite/model_visible_layout.rs | 40 +++++++++++++------ codex-rs/core/tests/suite/otel.rs | 7 ++-- codex-rs/core/tests/suite/tools.rs | 38 +++++++++--------- codex-rs/core/tests/suite/user_shell_cmd.rs | 16 +++++--- 6 files changed, 78 insertions(+), 48 deletions(-) diff --git a/codex-rs/core/tests/suite/code_mode.rs b/codex-rs/core/tests/suite/code_mode.rs index 413fd90bbb..af94252c02 100644 --- a/codex-rs/core/tests/suite/code_mode.rs +++ b/codex-rs/core/tests/suite/code_mode.rs @@ -11,10 +11,10 @@ use codex_models_manager::bundled_models_response; use codex_protocol::dynamic_tools::DynamicToolCallOutputContentItem; use codex_protocol::dynamic_tools::DynamicToolResponse; use codex_protocol::dynamic_tools::DynamicToolSpec; +use codex_protocol::models::PermissionProfile; use codex_protocol::protocol::AskForApproval; use codex_protocol::protocol::EventMsg; use codex_protocol::protocol::Op; -use codex_protocol::protocol::SandboxPolicy; use codex_protocol::user_input::UserInput; use core_test_support::apps_test_server::AppsTestServer; use core_test_support::assert_regex_match; @@ -30,6 +30,7 @@ use core_test_support::skip_if_no_network; use core_test_support::stdio_server_bin; use core_test_support::test_codex::TestCodex; use core_test_support::test_codex::test_codex; +use core_test_support::test_codex::turn_permission_fields; use core_test_support::wait_for_event; use core_test_support::wait_for_event_match; use pretty_assertions::assert_eq; @@ -2607,6 +2608,10 @@ text( ) .await; + let cwd = test.cwd.path().to_path_buf(); + let (sandbox_policy, permission_profile) = + turn_permission_fields(PermissionProfile::Disabled, cwd.as_path()); + test.codex .submit(Op::UserTurn { environments: None, @@ -2615,11 +2620,11 @@ text( text_elements: Vec::new(), }], final_output_json_schema: None, - cwd: test.cwd.path().to_path_buf(), + cwd, approval_policy: AskForApproval::Never, approvals_reviewer: None, - sandbox_policy: SandboxPolicy::DangerFullAccess, - permission_profile: None, + sandbox_policy, + permission_profile, model: test.session_configured.model.clone(), effort: None, summary: None, diff --git a/codex-rs/core/tests/suite/codex_delegate.rs b/codex-rs/core/tests/suite/codex_delegate.rs index 461b07284c..2ccb6fecba 100644 --- a/codex-rs/core/tests/suite/codex_delegate.rs +++ b/codex-rs/core/tests/suite/codex_delegate.rs @@ -1,12 +1,12 @@ use codex_core::config::Constrained; use codex_core::sandboxing::SandboxPermissions; +use codex_protocol::models::PermissionProfile; use codex_protocol::protocol::AskForApproval; use codex_protocol::protocol::EventMsg; use codex_protocol::protocol::Op; use codex_protocol::protocol::ReviewDecision; use codex_protocol::protocol::ReviewRequest; use codex_protocol::protocol::ReviewTarget; -use codex_protocol::protocol::SandboxPolicy; use core_test_support::responses::ev_apply_patch_function_call; use core_test_support::responses::ev_assistant_message; use core_test_support::responses::ev_completed; @@ -65,8 +65,9 @@ async fn codex_delegate_forwards_exec_approval_and_proceeds_on_approval() { let mut builder = test_codex().with_model("gpt-5.4").with_config(|config| { config.permissions.approval_policy = Constrained::allow_any(AskForApproval::OnRequest); config - .set_legacy_sandbox_policy(SandboxPolicy::new_read_only_policy()) - .expect("set sandbox policy"); + .permissions + .set_permission_profile(PermissionProfile::read_only()) + .expect("set permission profile"); }); let test = builder.build(&server).await.expect("build test codex"); @@ -149,8 +150,9 @@ async fn codex_delegate_forwards_patch_approval_and_proceeds_on_decision() { config.permissions.approval_policy = Constrained::allow_any(AskForApproval::OnRequest); // Use a restricted sandbox so patch approval is required config - .set_legacy_sandbox_policy(SandboxPolicy::new_read_only_policy()) - .expect("set sandbox policy"); + .permissions + .set_permission_profile(PermissionProfile::read_only()) + .expect("set permission profile"); config.include_apply_patch_tool = true; }); let test = builder.build(&server).await.expect("build test codex"); diff --git a/codex-rs/core/tests/suite/model_visible_layout.rs b/codex-rs/core/tests/suite/model_visible_layout.rs index 2f06d5af21..7ae148788e 100644 --- a/codex-rs/core/tests/suite/model_visible_layout.rs +++ b/codex-rs/core/tests/suite/model_visible_layout.rs @@ -6,10 +6,10 @@ use std::sync::Arc; use anyhow::Result; use codex_config::types::Personality; use codex_features::Feature; +use codex_protocol::models::PermissionProfile; use codex_protocol::protocol::AskForApproval; use codex_protocol::protocol::EventMsg; use codex_protocol::protocol::Op; -use codex_protocol::protocol::SandboxPolicy; use codex_protocol::user_input::UserInput; use core_test_support::context_snapshot; use core_test_support::context_snapshot::ContextSnapshotOptions; @@ -24,6 +24,7 @@ use core_test_support::responses::sse; use core_test_support::responses::start_mock_server; use core_test_support::skip_if_no_network; use core_test_support::test_codex::test_codex; +use core_test_support::test_codex::turn_permission_fields; use core_test_support::wait_for_event; use serde_json::json; @@ -111,6 +112,9 @@ async fn snapshot_model_visible_layout_turn_overrides() -> Result<()> { let test = builder.build(&server).await?; let preturn_context_diff_cwd = test.cwd_path().join(PRETURN_CONTEXT_DIFF_CWD); fs::create_dir_all(&preturn_context_diff_cwd)?; + let first_turn_cwd = test.cwd_path().to_path_buf(); + let (first_sandbox_policy, first_permission_profile) = + turn_permission_fields(PermissionProfile::read_only(), first_turn_cwd.as_path()); test.codex .submit(Op::UserTurn { @@ -120,11 +124,11 @@ async fn snapshot_model_visible_layout_turn_overrides() -> Result<()> { text_elements: Vec::new(), }], final_output_json_schema: None, - cwd: test.cwd_path().to_path_buf(), + cwd: first_turn_cwd, approval_policy: AskForApproval::Never, approvals_reviewer: None, - sandbox_policy: SandboxPolicy::new_read_only_policy(), - permission_profile: None, + sandbox_policy: first_sandbox_policy, + permission_profile: first_permission_profile, model: test.session_configured.model.clone(), effort: test.config.model_reasoning_effort, summary: None, @@ -138,6 +142,10 @@ async fn snapshot_model_visible_layout_turn_overrides() -> Result<()> { }) .await; + let (second_sandbox_policy, second_permission_profile) = turn_permission_fields( + PermissionProfile::read_only(), + preturn_context_diff_cwd.as_path(), + ); test.codex .submit(Op::UserTurn { environments: None, @@ -149,8 +157,8 @@ async fn snapshot_model_visible_layout_turn_overrides() -> Result<()> { cwd: preturn_context_diff_cwd, approval_policy: AskForApproval::OnRequest, approvals_reviewer: None, - sandbox_policy: SandboxPolicy::new_read_only_policy(), - permission_profile: None, + sandbox_policy: second_sandbox_policy, + permission_profile: second_permission_profile, model: test.session_configured.model.clone(), effort: test.config.model_reasoning_effort, summary: None, @@ -218,6 +226,8 @@ async fn snapshot_model_visible_layout_cwd_change_does_not_refresh_agents() -> R cwd_two.join("AGENTS.md"), "# AGENTS two\n\n\nTurn two agents instructions.\n\n", )?; + let (first_sandbox_policy, first_permission_profile) = + turn_permission_fields(PermissionProfile::read_only(), cwd_one.as_path()); test.codex .submit(Op::UserTurn { @@ -230,8 +240,8 @@ async fn snapshot_model_visible_layout_cwd_change_does_not_refresh_agents() -> R cwd: cwd_one.clone(), approval_policy: AskForApproval::Never, approvals_reviewer: None, - sandbox_policy: SandboxPolicy::new_read_only_policy(), - permission_profile: None, + sandbox_policy: first_sandbox_policy, + permission_profile: first_permission_profile, model: test.session_configured.model.clone(), effort: test.config.model_reasoning_effort, summary: None, @@ -245,6 +255,8 @@ async fn snapshot_model_visible_layout_cwd_change_does_not_refresh_agents() -> R }) .await; + let (second_sandbox_policy, second_permission_profile) = + turn_permission_fields(PermissionProfile::read_only(), cwd_two.as_path()); test.codex .submit(Op::UserTurn { environments: None, @@ -256,8 +268,8 @@ async fn snapshot_model_visible_layout_cwd_change_does_not_refresh_agents() -> R cwd: cwd_two, approval_policy: AskForApproval::Never, approvals_reviewer: None, - sandbox_policy: SandboxPolicy::new_read_only_policy(), - permission_profile: None, + sandbox_policy: second_sandbox_policy, + permission_profile: second_permission_profile, model: test.session_configured.model.clone(), effort: test.config.model_reasoning_effort, summary: None, @@ -358,6 +370,10 @@ async fn snapshot_model_visible_layout_resume_with_personality_change() -> Resul let resumed = resume_builder.resume(&server, home, rollout_path).await?; let resume_override_cwd = resumed.cwd_path().join(PRETURN_CONTEXT_DIFF_CWD); fs::create_dir_all(&resume_override_cwd)?; + let (sandbox_policy, permission_profile) = turn_permission_fields( + PermissionProfile::read_only(), + resume_override_cwd.as_path(), + ); resumed .codex .submit(Op::UserTurn { @@ -370,8 +386,8 @@ async fn snapshot_model_visible_layout_resume_with_personality_change() -> Resul cwd: resume_override_cwd, approval_policy: AskForApproval::Never, approvals_reviewer: None, - sandbox_policy: SandboxPolicy::new_read_only_policy(), - permission_profile: None, + sandbox_policy, + permission_profile, model: resumed.session_configured.model.clone(), effort: resumed.config.model_reasoning_effort, summary: None, diff --git a/codex-rs/core/tests/suite/otel.rs b/codex-rs/core/tests/suite/otel.rs index 8d0d4d79a7..deeffcd855 100644 --- a/codex-rs/core/tests/suite/otel.rs +++ b/codex-rs/core/tests/suite/otel.rs @@ -1,10 +1,10 @@ use codex_core::config::Constrained; use codex_features::Feature; +use codex_protocol::models::PermissionProfile; use codex_protocol::protocol::AskForApproval; use codex_protocol::protocol::EventMsg; use codex_protocol::protocol::Op; use codex_protocol::protocol::ReviewDecision; -use codex_protocol::protocol::SandboxPolicy; use codex_protocol::user_input::UserInput; use core_test_support::responses::ev_assistant_message; use core_test_support::responses::ev_completed; @@ -1196,8 +1196,9 @@ async fn handle_container_exec_autoapprove_from_config_records_tool_decision() { .with_config(|config| { config.permissions.approval_policy = Constrained::allow_any(AskForApproval::OnRequest); config - .set_legacy_sandbox_policy(SandboxPolicy::DangerFullAccess) - .expect("set sandbox policy"); + .permissions + .set_permission_profile(PermissionProfile::Disabled) + .expect("set permission profile"); }) .build(&server) .await diff --git a/codex-rs/core/tests/suite/tools.rs b/codex-rs/core/tests/suite/tools.rs index aff8755b11..46195e4dd0 100644 --- a/codex-rs/core/tests/suite/tools.rs +++ b/codex-rs/core/tests/suite/tools.rs @@ -190,10 +190,10 @@ async fn custom_tool_unknown_returns_custom_output_error() -> Result<()> { ) .await; - test.submit_turn_with_policies( + test.submit_turn_with_approval_and_permission_profile( "invoke custom tool", AskForApproval::Never, - SandboxPolicy::DangerFullAccess, + PermissionProfile::Disabled, ) .await?; @@ -408,10 +408,10 @@ async fn shell_escalated_permissions_rejected_then_ok() -> Result<()> { ) .await; - test.submit_turn_with_policies( + test.submit_turn_with_approval_and_permission_profile( "run the shell command", AskForApproval::Never, - SandboxPolicy::DangerFullAccess, + PermissionProfile::Disabled, ) .await?; @@ -488,9 +488,9 @@ async fn sandbox_denied_shell_returns_original_output() -> Result<()> { let mock = mount_sse_sequence(&server, responses).await; fixture - .submit_turn_with_policy( + .submit_turn_with_permission_profile( "run a command that should be denied by the read-only sandbox", - SandboxPolicy::new_read_only_policy(), + PermissionProfile::read_only(), ) .await?; @@ -675,10 +675,10 @@ async fn collect_tools(use_unified_exec: bool) -> Result> { }); let test = builder.build(&server).await?; - test.submit_turn_with_policies( + test.submit_turn_with_approval_and_permission_profile( "list tools", AskForApproval::Never, - SandboxPolicy::DangerFullAccess, + PermissionProfile::Disabled, ) .await?; @@ -746,10 +746,10 @@ async fn shell_timeout_includes_timeout_prefix_and_metadata() -> Result<()> { ) .await; - test.submit_turn_with_policies( + test.submit_turn_with_approval_and_permission_profile( "run a long command", AskForApproval::Never, - SandboxPolicy::DangerFullAccess, + PermissionProfile::Disabled, ) .await?; @@ -791,8 +791,9 @@ async fn shell_timeout_handles_background_grandchild_stdout() -> Result<()> { let server = start_mock_server().await; let mut builder = test_codex().with_model("gpt-5.4").with_config(|config| { config - .set_legacy_sandbox_policy(SandboxPolicy::DangerFullAccess) - .expect("set sandbox policy"); + .permissions + .set_permission_profile(PermissionProfile::Disabled) + .expect("set permission profile"); }); let test = builder.build(&server).await?; @@ -837,10 +838,10 @@ time.sleep(60) let start = Instant::now(); let output_str = tokio::time::timeout(Duration::from_secs(10), async { - test.submit_turn_with_policies( + test.submit_turn_with_approval_and_permission_profile( "run a command with a detached grandchild", AskForApproval::Never, - SandboxPolicy::DangerFullAccess, + PermissionProfile::Disabled, ) .await?; let timeout_item = second_mock.single_request().function_call_output(call_id); @@ -885,8 +886,9 @@ async fn shell_spawn_failure_truncates_exec_error() -> Result<()> { let server = start_mock_server().await; let mut builder = test_codex().with_config(|cfg| { - cfg.set_legacy_sandbox_policy(SandboxPolicy::DangerFullAccess) - .expect("set sandbox policy"); + cfg.permissions + .set_permission_profile(PermissionProfile::Disabled) + .expect("set permission profile"); }); let test = builder.build(&server).await?; @@ -922,10 +924,10 @@ async fn shell_spawn_failure_truncates_exec_error() -> Result<()> { ) .await; - test.submit_turn_with_policies( + test.submit_turn_with_approval_and_permission_profile( "spawn a missing binary", AskForApproval::Never, - SandboxPolicy::DangerFullAccess, + PermissionProfile::Disabled, ) .await?; diff --git a/codex-rs/core/tests/suite/user_shell_cmd.rs b/codex-rs/core/tests/suite/user_shell_cmd.rs index 5526356693..1285b9f925 100644 --- a/codex-rs/core/tests/suite/user_shell_cmd.rs +++ b/codex-rs/core/tests/suite/user_shell_cmd.rs @@ -8,7 +8,6 @@ use codex_protocol::protocol::ExecCommandEndEvent; use codex_protocol::protocol::ExecCommandSource; use codex_protocol::protocol::ExecOutputStream; use codex_protocol::protocol::Op; -use codex_protocol::protocol::SandboxPolicy; use codex_protocol::protocol::TurnAbortReason; use codex_protocol::user_input::UserInput; use core_test_support::PathBufExt; @@ -23,6 +22,7 @@ use core_test_support::responses::sse; use core_test_support::responses::start_mock_server; use core_test_support::skip_if_no_network; use core_test_support::test_codex::test_codex; +use core_test_support::test_codex::turn_permission_fields; use core_test_support::wait_for_event; use core_test_support::wait_for_event_match; use core_test_support::wait_for_event_with_timeout; @@ -168,6 +168,10 @@ async fn user_shell_command_does_not_replace_active_turn() -> anyhow::Result<()> ]); let mock = responses::mount_sse_sequence(&server, vec![first, second]).await; + let cwd = fixture.cwd.path().to_path_buf(); + let (sandbox_policy, permission_profile) = + turn_permission_fields(PermissionProfile::Disabled, cwd.as_path()); + fixture .codex .submit(Op::UserTurn { @@ -177,11 +181,11 @@ async fn user_shell_command_does_not_replace_active_turn() -> anyhow::Result<()> text_elements: Vec::new(), }], final_output_json_schema: None, - cwd: fixture.cwd.path().to_path_buf(), + cwd, approval_policy: AskForApproval::Never, approvals_reviewer: None, - sandbox_policy: SandboxPolicy::DangerFullAccess, - permission_profile: None, + sandbox_policy, + permission_profile, model: fixture.session_configured.model.clone(), effort: None, summary: None, @@ -484,9 +488,9 @@ async fn user_shell_command_is_truncated_only_once() -> anyhow::Result<()> { .await; fixture - .submit_turn_with_policy( + .submit_turn_with_permission_profile( "trigger big shell_command output", - SandboxPolicy::DangerFullAccess, + PermissionProfile::Disabled, ) .await?;