mirror of
https://github.com/openai/codex.git
synced 2026-05-24 21:14:51 +00:00
## Why This continues the permissions migration by keeping the TUI command boundary aligned with the app-server protocol direction from #22795: callers should select a permission profile by id instead of passing a concrete `PermissionProfile` value around as the turn configuration. `AppCommand` is internal to the TUI, but it is the path that eventually becomes `thread/turn/start`, so carrying concrete profile details there made it too easy for UI code to keep relying on the old whole-profile replacement model. ## What changed - `AppCommand::UserTurn` and `AppCommand::OverrideTurnContext` now carry `Option<ActivePermissionProfile>` instead of `PermissionProfile`. - Composer submissions copy the active permission profile id from the current session snapshot; legacy snapshots intentionally submit no active profile id. - Permission preset UI events now carry only the active built-in profile id. The app derives the concrete built-in `PermissionProfile` internally only when updating its local config/status snapshot. - Permission presets expose their built-in active profile id, and preset selection preserves that id in both the immediate turn override and the local TUI config snapshot. - Turn routing sends `TurnPermissionsOverride::ActiveProfile` when an active id is present, and only falls back to the legacy sandbox projection for the remaining runtime override path. ## How to review Start with `codex-rs/tui/src/app_command.rs` to verify the command shape no longer exposes `PermissionProfile`. Then read `codex-rs/tui/src/app/thread_routing.rs` to verify the app-server turn-start conversion: active ids go through as ids, while the legacy sandbox fallback is still constrained to the existing runtime override case. Finally, check `codex-rs/tui/src/chatwidget/permission_popups.rs`, `codex-rs/tui/src/app/event_dispatch.rs`, `codex-rs/tui/src/app/config_persistence.rs`, and `codex-rs/utils/approval-presets/src/lib.rs` to see how preset selections stay id-only across TUI events while the local display/config mirror still gets a concrete built-in profile. ## Verification Latest local verification after the id-only `AppEvent` cleanup: - `cargo check -p codex-tui --tests` - `cargo test -p codex-tui permissions_selection_sends_approvals_reviewer_in_override_turn_context` - `cargo test -p codex-tui update_feature_flags_enabling_guardian` - `cargo test -p codex-utils-approval-presets` - `just fmt` - `just fix -p codex-tui -p codex-utils-approval-presets` Earlier in the same PR, before the final event-shape cleanup: - `cargo test -p codex-tui turn_permissions_` - `cargo test -p codex-tui submission_` - `cargo test -p codex-tui session_configured_syncs_widget_config_permissions_and_cwd` - `RUST_MIN_STACK=16777216 cargo test -p codex-tui`
78 lines
3.3 KiB
Rust
78 lines
3.3 KiB
Rust
use codex_protocol::models::ActivePermissionProfile;
|
|
use codex_protocol::models::BUILT_IN_PERMISSION_PROFILE_DANGER_FULL_ACCESS;
|
|
use codex_protocol::models::BUILT_IN_PERMISSION_PROFILE_READ_ONLY;
|
|
use codex_protocol::models::BUILT_IN_PERMISSION_PROFILE_WORKSPACE;
|
|
use codex_protocol::models::PermissionProfile;
|
|
use codex_protocol::protocol::AskForApproval;
|
|
|
|
/// A simple preset pairing an approval policy with a permission profile.
|
|
#[derive(Debug, Clone)]
|
|
pub struct ApprovalPreset {
|
|
/// Stable identifier for the preset.
|
|
pub id: &'static str,
|
|
/// Display label shown in UIs.
|
|
pub label: &'static str,
|
|
/// Short human description shown next to the label in UIs.
|
|
pub description: &'static str,
|
|
/// Approval policy to apply.
|
|
pub approval: AskForApproval,
|
|
/// Built-in permission profile selected by this preset.
|
|
pub active_permission_profile: ActivePermissionProfile,
|
|
/// Permission profile to apply.
|
|
pub permission_profile: PermissionProfile,
|
|
}
|
|
|
|
/// Built-in list of approval presets that pair approval and permissions.
|
|
///
|
|
/// Keep this UI-agnostic so it can be reused by both TUI and MCP server.
|
|
pub fn builtin_approval_presets() -> Vec<ApprovalPreset> {
|
|
vec![
|
|
ApprovalPreset {
|
|
id: "read-only",
|
|
label: "Read Only",
|
|
description: "Codex can read files in the current workspace. Approval is required to edit files or access the internet.",
|
|
approval: AskForApproval::OnRequest,
|
|
active_permission_profile: ActivePermissionProfile::new(
|
|
BUILT_IN_PERMISSION_PROFILE_READ_ONLY,
|
|
),
|
|
permission_profile: PermissionProfile::read_only(),
|
|
},
|
|
ApprovalPreset {
|
|
id: "auto",
|
|
label: "Default",
|
|
description: "Codex can read and edit files in the current workspace, and run commands. Approval is required to access the internet or edit other files. (Identical to Agent mode)",
|
|
approval: AskForApproval::OnRequest,
|
|
active_permission_profile: ActivePermissionProfile::new(
|
|
BUILT_IN_PERMISSION_PROFILE_WORKSPACE,
|
|
),
|
|
permission_profile: PermissionProfile::workspace_write(),
|
|
},
|
|
ApprovalPreset {
|
|
id: "full-access",
|
|
label: "Full Access",
|
|
description: "Codex can edit files outside this workspace and access the internet without asking for approval. Exercise caution when using.",
|
|
approval: AskForApproval::Never,
|
|
active_permission_profile: ActivePermissionProfile::new(
|
|
BUILT_IN_PERMISSION_PROFILE_DANGER_FULL_ACCESS,
|
|
),
|
|
permission_profile: PermissionProfile::Disabled,
|
|
},
|
|
]
|
|
}
|
|
|
|
/// Return the concrete profile for one of the built-in active profile ids.
|
|
pub fn builtin_permission_profile_for_active_permission_profile(
|
|
active_permission_profile: &ActivePermissionProfile,
|
|
) -> Option<PermissionProfile> {
|
|
if active_permission_profile.extends.is_some() {
|
|
return None;
|
|
}
|
|
|
|
match active_permission_profile.id.as_str() {
|
|
BUILT_IN_PERMISSION_PROFILE_READ_ONLY => Some(PermissionProfile::read_only()),
|
|
BUILT_IN_PERMISSION_PROFILE_WORKSPACE => Some(PermissionProfile::workspace_write()),
|
|
BUILT_IN_PERMISSION_PROFILE_DANGER_FULL_ACCESS => Some(PermissionProfile::Disabled),
|
|
_ => None,
|
|
}
|
|
}
|