mirror of
https://github.com/openai/codex.git
synced 2026-05-03 02:46:39 +00:00
feat: introduce Permissions (#11633)
## Why We currently carry multiple permission-related concepts directly on `Config` for shell/unified-exec behavior (`approval_policy`, `sandbox_policy`, `network`, `shell_environment_policy`, `windows_sandbox_mode`). Consolidating these into one in-memory struct makes permission handling easier to reason about and sets up the next step: supporting named permission profiles (`[permissions.PROFILE_NAME]`) without changing behavior now. This change is mostly mechanical: it updates existing callsites to go through `config.permissions`, but it does not yet refactor those callsites to take a single `Permissions` value in places where multiple permission fields are still threaded separately. This PR intentionally **does not** change the on-disk `config.toml` format yet and keeps compatibility with legacy config keys. ## What Changed - Introduced `Permissions` in `core/src/config/mod.rs`. - Added `Config::permissions` and moved effective runtime permission fields under it: - `approval_policy` - `sandbox_policy` - `network` - `shell_environment_policy` - `windows_sandbox_mode` - Updated config loading/building so these effective values are still derived from the same existing config inputs and constraints. - Updated Windows sandbox helpers/resolution to read/write via `permissions`. - Threaded the new field through all permission consumers across core runtime, app-server, CLI/exec, TUI, and sandbox summary code. - Updated affected tests to reference `config.permissions.*`. - Renamed the struct/field from `EffectivePermissions`/`effective_permissions` to `Permissions`/`permissions` and aligned variable naming accordingly. ## Verification - `just fix -p codex-core -p codex-tui -p codex-cli -p codex-app-server -p codex-exec -p codex-utils-sandbox-summary` - `cargo build -p codex-core -p codex-tui -p codex-cli -p codex-app-server -p codex-exec -p codex-utils-sandbox-summary`
This commit is contained in:
@@ -4510,7 +4510,7 @@ async fn disabled_slash_command_while_task_running_snapshot() {
|
||||
async fn approvals_popup_shows_disabled_presets() {
|
||||
let (mut chat, _rx, _op_rx) = make_chatwidget_manual(None).await;
|
||||
|
||||
chat.config.approval_policy =
|
||||
chat.config.permissions.approval_policy =
|
||||
Constrained::new(AskForApproval::OnRequest, |candidate| match candidate {
|
||||
AskForApproval::OnRequest => Ok(()),
|
||||
_ => Err(invalid_value(
|
||||
@@ -4546,7 +4546,7 @@ async fn approvals_popup_shows_disabled_presets() {
|
||||
async fn approvals_popup_navigation_skips_disabled() {
|
||||
let (mut chat, mut rx, mut op_rx) = make_chatwidget_manual(None).await;
|
||||
|
||||
chat.config.approval_policy =
|
||||
chat.config.permissions.approval_policy =
|
||||
Constrained::new(AskForApproval::OnRequest, |candidate| match candidate {
|
||||
AskForApproval::OnRequest => Ok(()),
|
||||
_ => Err(invalid_value(candidate.to_string(), "[on-request]")),
|
||||
@@ -4623,7 +4623,10 @@ async fn approval_modal_exec_snapshot() -> anyhow::Result<()> {
|
||||
// Build a chat widget with manual channels to avoid spawning the agent.
|
||||
let (mut chat, _rx, _op_rx) = make_chatwidget_manual(None).await;
|
||||
// Ensure policy allows surfacing approvals explicitly (not strictly required for direct event).
|
||||
chat.config.approval_policy.set(AskForApproval::OnRequest)?;
|
||||
chat.config
|
||||
.permissions
|
||||
.approval_policy
|
||||
.set(AskForApproval::OnRequest)?;
|
||||
// Inject an exec approval request to display the approval modal.
|
||||
let ev = ExecApprovalRequestEvent {
|
||||
call_id: "call-approve-cmd".into(),
|
||||
@@ -4678,7 +4681,10 @@ async fn approval_modal_exec_snapshot() -> anyhow::Result<()> {
|
||||
#[tokio::test]
|
||||
async fn approval_modal_exec_without_reason_snapshot() -> anyhow::Result<()> {
|
||||
let (mut chat, _rx, _op_rx) = make_chatwidget_manual(None).await;
|
||||
chat.config.approval_policy.set(AskForApproval::OnRequest)?;
|
||||
chat.config
|
||||
.permissions
|
||||
.approval_policy
|
||||
.set(AskForApproval::OnRequest)?;
|
||||
|
||||
let ev = ExecApprovalRequestEvent {
|
||||
call_id: "call-approve-cmd-noreason".into(),
|
||||
@@ -4720,7 +4726,10 @@ async fn approval_modal_exec_without_reason_snapshot() -> anyhow::Result<()> {
|
||||
async fn approval_modal_exec_multiline_prefix_hides_execpolicy_option_snapshot()
|
||||
-> anyhow::Result<()> {
|
||||
let (mut chat, _rx, _op_rx) = make_chatwidget_manual(None).await;
|
||||
chat.config.approval_policy.set(AskForApproval::OnRequest)?;
|
||||
chat.config
|
||||
.permissions
|
||||
.approval_policy
|
||||
.set(AskForApproval::OnRequest)?;
|
||||
|
||||
let script = "python - <<'PY'\nprint('hello')\nPY".to_string();
|
||||
let command = vec!["bash".into(), "-lc".into(), script];
|
||||
@@ -4760,7 +4769,10 @@ async fn approval_modal_exec_multiline_prefix_hides_execpolicy_option_snapshot()
|
||||
#[tokio::test]
|
||||
async fn approval_modal_patch_snapshot() -> anyhow::Result<()> {
|
||||
let (mut chat, _rx, _op_rx) = make_chatwidget_manual(None).await;
|
||||
chat.config.approval_policy.set(AskForApproval::OnRequest)?;
|
||||
chat.config
|
||||
.permissions
|
||||
.approval_policy
|
||||
.set(AskForApproval::OnRequest)?;
|
||||
|
||||
// Build a small changeset and a reason/grant_root to exercise the prompt text.
|
||||
let mut changes = HashMap::new();
|
||||
@@ -5529,7 +5541,10 @@ async fn apply_patch_full_flow_integration_like() {
|
||||
async fn apply_patch_untrusted_shows_approval_modal() -> anyhow::Result<()> {
|
||||
let (mut chat, _rx, _op_rx) = make_chatwidget_manual(None).await;
|
||||
// Ensure approval policy is untrusted (OnRequest)
|
||||
chat.config.approval_policy.set(AskForApproval::OnRequest)?;
|
||||
chat.config
|
||||
.permissions
|
||||
.approval_policy
|
||||
.set(AskForApproval::OnRequest)?;
|
||||
|
||||
// Simulate a patch approval request from backend
|
||||
let mut changes = HashMap::new();
|
||||
@@ -5577,7 +5592,10 @@ async fn apply_patch_request_shows_diff_summary() -> anyhow::Result<()> {
|
||||
let (mut chat, mut rx, _op_rx) = make_chatwidget_manual(None).await;
|
||||
|
||||
// Ensure we are in OnRequest so an approval is surfaced
|
||||
chat.config.approval_policy.set(AskForApproval::OnRequest)?;
|
||||
chat.config
|
||||
.permissions
|
||||
.approval_policy
|
||||
.set(AskForApproval::OnRequest)?;
|
||||
|
||||
// Simulate backend asking to apply a patch adding two lines to README.md
|
||||
let mut changes = HashMap::new();
|
||||
|
||||
Reference in New Issue
Block a user