permissions: centralize legacy sandbox projection (#19734)

## Why

The remaining migration work still needs `SandboxPolicy` at a few
compatibility boundaries, but those projections should come from one
canonical path. Keeping ad hoc legacy projections scattered through
app-server, CLI, and config code makes it easy for behavior to drift as
`PermissionProfile` gains fidelity that the legacy enum cannot
represent.

## What Changed

- Adds `Permissions::legacy_sandbox_policy(cwd)` and
`Config::legacy_sandbox_policy()` as the compatibility projection from
the canonical `PermissionProfile`.
- Adds `Permissions::can_set_legacy_sandbox_policy()` so legacy inputs
are checked after they are converted into profile semantics.
- Updates app-server command handling, Windows sandbox setup, session
configuration, and sandbox summaries to use the centralized projection
helper.
- Leaves `SandboxPolicy` in place only for boundary inputs/outputs that
still speak the legacy abstraction.

## Verification

- `cargo check -p codex-config -p codex-core -p codex-sandboxing -p
codex-app-server -p codex-cli -p codex-tui`
- `cargo test -p codex-tui
permissions_selection_history_snapshot_full_access_to_default --
--nocapture`
- `cargo test -p codex-tui
permissions_selection_sends_approvals_reviewer_in_override_turn_context
-- --nocapture`
- `bazel test //codex-rs/tui:tui-unit-tests-bin
--test_arg=permissions_selection_history_snapshot_full_access_to_default
--test_output=errors`
- `bazel test //codex-rs/tui:tui-unit-tests-bin
--test_arg=permissions_selection_sends_approvals_reviewer_in_override_turn_context
--test_output=errors`


---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/openai/codex/pull/19734).
* #19737
* #19736
* #19735
* __->__ #19734
This commit is contained in:
Michael Bolin
2026-04-26 20:31:23 -07:00
committed by GitHub
parent c3e60849e5
commit 0d8cdc0510
16 changed files with 210 additions and 86 deletions
@@ -1,6 +1,13 @@
use super::*;
use pretty_assertions::assert_eq;
fn set_legacy_sandbox_policy(chat: &mut ChatWidget, sandbox_policy: SandboxPolicy) {
chat.config
.permissions
.set_legacy_sandbox_policy(sandbox_policy, chat.config.cwd.as_path())
.expect("set sandbox policy");
}
#[tokio::test]
async fn approvals_selection_popup_snapshot() {
let (mut chat, _rx, _op_rx) = make_chatwidget_manual(/*model_override*/ None).await;
@@ -347,8 +354,7 @@ async fn permissions_selection_history_snapshot_full_access_to_default() {
.approval_policy
.set(AskForApproval::Never)
.expect("set approval policy");
chat.config.permissions.sandbox_policy =
Constrained::allow_any(SandboxPolicy::DangerFullAccess);
set_legacy_sandbox_policy(&mut chat, SandboxPolicy::DangerFullAccess);
chat.open_permissions_popup();
let popup = render_bottom_popup(&chat, /*width*/ 120);
@@ -387,11 +393,7 @@ async fn permissions_selection_emits_history_cell_when_current_is_selected() {
.approval_policy
.set(AskForApproval::OnRequest)
.expect("set approval policy");
chat.config
.permissions
.sandbox_policy
.set(SandboxPolicy::new_workspace_write_policy())
.expect("set sandbox policy");
set_legacy_sandbox_policy(&mut chat, SandboxPolicy::new_workspace_write_policy());
chat.open_permissions_popup();
chat.handle_key_event(KeyEvent::from(KeyCode::Enter));
@@ -446,11 +448,7 @@ async fn permissions_selection_hides_auto_review_when_feature_disabled_even_if_a
.approval_policy
.set(AskForApproval::OnRequest)
.expect("set approval policy");
chat.config
.permissions
.sandbox_policy
.set(SandboxPolicy::new_workspace_write_policy())
.expect("set sandbox policy");
set_legacy_sandbox_policy(&mut chat, SandboxPolicy::new_workspace_write_policy());
chat.open_permissions_popup();
let popup = render_bottom_popup(&chat, /*width*/ 120);
@@ -575,11 +573,7 @@ async fn permissions_selection_can_disable_auto_review() {
.approval_policy
.set(AskForApproval::OnRequest)
.expect("set approval policy");
chat.config
.permissions
.sandbox_policy
.set(SandboxPolicy::new_workspace_write_policy())
.expect("set sandbox policy");
set_legacy_sandbox_policy(&mut chat, SandboxPolicy::new_workspace_write_policy());
chat.open_permissions_popup();
chat.handle_key_event(KeyEvent::from(KeyCode::Up));
@@ -616,11 +610,7 @@ async fn permissions_selection_sends_approvals_reviewer_in_override_turn_context
.approval_policy
.set(AskForApproval::OnRequest)
.expect("set approval policy");
chat.config
.permissions
.sandbox_policy
.set(SandboxPolicy::new_workspace_write_policy())
.expect("set sandbox policy");
set_legacy_sandbox_policy(&mut chat, SandboxPolicy::new_workspace_write_policy());
chat.set_approvals_reviewer(ApprovalsReviewer::User);
chat.open_permissions_popup();