tui: add named permission profile picker#21559
Conversation
fcoury-oai
left a comment
There was a problem hiding this comment.
I found a potential issue with the help of Codex:
When I switch to a different named profile mid-session, the TUI updates correctly and /status shows the new profile.
But then the already-running session does not fully adopt that profile’s runtime state.
It seems like switching from a profile with no managed network proxy to one with profile-specific network policy leaves the live thread on the old proxy/network behavior.
So the UI says “profile B is active,” but the current session can still behave like profile A until a fresh session/thread is started.
Repro
This is the exact repro steps I used to replicate this issue.
Setup in ~/.codex/config.toml:
default_permissions = "locked-down"
[permissions.locked-down.filesystem]
":minimal" = "read"
[permissions.web-enabled.filesystem]
":minimal" = "read"
[permissions.web-enabled.filesystem.":project_roots"]
"." = "write"
[permissions.web-enabled.network]
enabled = true
allow_local_binding = true
[permissions.web-enabled.network.domains]
"example.com" = "allow"Important shape of the two profiles:
locked-downhas no network stanza at allweb-enabledenables network and adds a profile-specific allowlist forexample.com
Steps
- Start a fresh Codex TUI session with
locked-downactive. - Send one trivial prompt so there is a live session/thread.
- Run
/debug-config.
Observed after step 3:
- no
Session runtimenetwork_proxyblock is shown
- Run
/permissionsand switch toweb-enabled. - Run
/status.
Observed after step 5:
/statusshowsPermissions: Profile web-enabled (...)
- Run
/debug-configagain, in the same session.
Observed after step 6:
- still no
Session runtimenetwork_proxyblock
- In that same session, ask Codex:
Use the shell tool to run 'curl -I https://openai.com'
Observed after step 7:
- the request goes out and reaches OpenAI
- I got a real HTTP response path, ending in a Cloudflare challenge (
HTTP/2 403,cf-mitigated: challenge), which means the outbound request was not blocked by the profile-specific allowlist
Expected
After switching to web-enabled, the live session should pick up the profile’s managed network policy. Since web-enabled only allows example.com, a shell-tool request to https://openai.com should be blocked.
Actual
The UI updates to web-enabled, but the live session does not appear to gain the managed proxy/runtime state for that profile:
/statusreflects the new profile/debug-configstill shows no sessionnetwork_proxy- shell-tool network behavior still allows
openai.com
Why this looks like the bug
This matches the code path concern that mid-session /permissions updates the TUI/app config copy, but the live-session override does not carry enough data to fully apply the selected named profile’s runtime network state. It reproduces specifically when switching from a profile with no managed proxy to one that requires a managed proxy.
|
Addressed the runtime proxy gap in b140e5f. What changed:
Local checks:
|
b8a0eec to
653089d
Compare
653089d to
71ea260
Compare
e1008e8 to
35c7271
Compare
## Why The `/permissions` picker needs a config-level way to distinguish legacy anonymous presets from named permission-profile mode. That signal cannot be inferred reliably in the TUI, especially for the edge case where `default_permissions = ":workspace"` is present without a `[permissions]` table. ## What changed - Expose whether the merged config is explicitly in permission-profile mode. - Expose the configured custom permission profile IDs alongside the built-in profile semantics. - Add regression coverage for profile mode detection and custom profile metadata, including the `default_permissions = ":workspace"` case. - Update the thread-manager sample config literal to match the expanded config shape. ## Stack 1. **This PR**: config metadata needed by downstream permission-profile consumers. 2. [#22931](#22931): refresh active permission profiles through runtime/session/network state. 3. [#21559](#21559): switch `/permissions` to the profile-aware TUI picker. ## Verification - `cargo check -p codex-thread-manager-sample` - `cargo test -p codex-core default_permissions_can_select_builtin_profile_without_permissions_table` - `cargo test -p codex-core permissions_profiles_allow_direct_write_roots_outside_workspace_root`
6206636 to
98b8aab
Compare
35c7271 to
9d4d30b
Compare
98b8aab to
6d4a8df
Compare
9d4d30b to
e1d6bf1
Compare
81b6cf4 to
843a29c
Compare
7514892 to
85d1f42
Compare
ce7ae38 to
ef21b6b
Compare
85d1f42 to
7cb4f6b
Compare
ef21b6b to
8e8150c
Compare
7cb4f6b to
39cb064
Compare
8e8150c to
c83b8db
Compare
39cb064 to
f6005e7
Compare
c83b8db to
3ee4233
Compare
f6005e7 to
dd22806
Compare
## Why Once a named permission profile is selected, runtime state has to keep that profile identity intact instead of collapsing back to anonymous effective permissions. The session refresh path also needs to rebuild profile-derived network proxy state so active profile switches take effect consistently. ## What changed - Preserve the active permission profile through session updates. - Rebuild profile-derived runtime/network configuration when the active profile changes. - Keep the runtime path aligned with the current session configuration APIs. - Tighten the affected tests, including the Windows delete-pending memory-file case that was intermittently tripping CI. ## Stack 1. **This PR**: runtime/session/network propagation for active permission profiles. 2. [#23708](#23708): TUI selection plumbing and guardrail flow. 3. [#21559](#21559): profile-aware `/permissions` menu and custom profile display. <img width="1296" height="906" alt="image" src="https://github.com/user-attachments/assets/077fa3a7-80cb-4925-80b1-d2395018d90a" />
## Why The named-profile `/permissions` picker needs a small TUI action path that can select permission profiles without folding the menu UI and profile metadata into the same review. ## What changed - Carry permission-profile selections through the TUI app event flow. - Persist selected profiles while preserving the existing approval settings and guardrail prompts. - Keep the legacy `/permissions` picker behavior in this layer; the profile-mode menu stays in the follow-up PR. ## Stack 1. [#22931](#22931): runtime/session/network propagation for active permission profiles. 2. **This PR**: TUI selection plumbing and guardrail flow. 3. [#21559](#21559): profile-aware `/permissions` menu and custom profile display. <img width="1632" height="1186" alt="image" src="https://github.com/user-attachments/assets/69ddcd5e-b57c-468d-8c1d-246916323c15" /> ## Validation - `git diff --cached --check` before commit. - Full test run skipped at the user request while pushing the split stack.
fcoury-oai
left a comment
There was a problem hiding this comment.
Smoke tested the happy path locally in profile mode with a temp CODEX_HOME/config.toml using default_permissions plus custom profiles.
Verified /permissions showed the profile-aware picker with friendly built-in labels and custom profile descriptions, selecting a custom profile emitted the expected “Permissions updated to …” message and became current on reopen, and switching back to Default preserved the friendly built-in label/current state.
Code looks good as well, approved. 👍
dd22806 to
5df6769
Compare
Co-authored-by: Codex noreply@openai.com
Co-authored-by: Codex noreply@openai.com
Co-authored-by: Codex noreply@openai.com
Co-authored-by: Codex noreply@openai.com
5df6769 to
e7e0e56
Compare
Why
Users who opt into named permission profiles through
default_permissionsor[permissions.*]should stay in named-profile semantics when they open/permissions. The legacy picker rewrites those users into anonymous preset state, which loses the active profile identity and hides custom configured profiles.What changed
/permissionsto a profile-aware picker when profile mode is active.:profile syntax.Stack
/permissionsmenu and custom profile display.UX impact
In profile mode,
/permissionsshows the same human-facing built-ins users already know:Selecting
locked-downkeepsactive_permission_profile = Some("locked-down"); selecting a built-in keeps the friendly label while switching to its named built-in profile.Screenshots
Live
$test-tuismoke screenshots uploaded through GitHub attachments:Profile mode with built-ins and custom profiles
Legacy mode remains anonymous preset picker
Validation
git diff --cached --checkbefore commit.