Skip to content

permissions: start migrating runtime state to PermissionProfile#15914

Open
bolinfest wants to merge 1 commit intomainfrom
pr15914
Open

permissions: start migrating runtime state to PermissionProfile#15914
bolinfest wants to merge 1 commit intomainfrom
pr15914

Conversation

@bolinfest
Copy link
Copy Markdown
Collaborator

@bolinfest bolinfest commented Mar 26, 2026

Why

SandboxPolicy is still acting as the thread-level source of truth for permissions, but it collapses richer filesystem and network state back into a lossy legacy enum. That makes it hard to preserve special filesystem entries and per-turn runtime overrides as we move toward PermissionProfile being the primary permission abstraction throughout the codebase.

This PR starts that migration by teaching PermissionProfile to represent the current runtime permissions, while keeping the existing constrained runtime policies as the authoritative state in core. That avoids introducing duplicated or ambiguous permission fields before PermissionProfile is lossless enough to fully replace the legacy runtime model.

What changed

  • replace FileSystemPermissions { read, write } with a canonical entries: Vec<FileSystemSandboxEntry> representation in protocol, while preserving legacy read/write serde compatibility for existing wire shapes
  • add helpers to derive PermissionProfile from runtime filesystem and network sandbox policies, plus compatibility helpers to project back to legacy SandboxPolicy when needed
  • keep core runtime state authoritative on the constrained split permission fields (sandbox_policy, filesystem, network, and macOS seatbelt extensions) rather than storing a second permission_profile field alongside them
  • preserve canonical filesystem approval scope across the app-server boundary by emitting entries when special paths or deny rules cannot be represented losslessly as legacy read/write lists
  • update the TUI and tui_app_server approval overlays to render special filesystem grants and deny entries instead of silently omitting them

Testing

  • cargo test -p codex-core default_permissions_profile_populates_runtime_sandbox_policy -- --nocapture
  • cargo test -p codex-core session_configuration_apply_preserves_split_file_system_policy_on_cwd_only_update -- --nocapture
  • cargo test -p codex-app-server-protocol
  • cargo test -p codex-tui -p codex-tui-app-server approval_overlay -- --nocapture
  • just write-app-server-schema
  • just fix -p codex-app-server-protocol -p codex-tui -p codex-tui-app-server
  • just argument-comment-lint

@bolinfest bolinfest changed the title permissions: start using PermissionProfile as the canonical runtime model permissions: start migrating runtime state to PermissionProfile Mar 26, 2026
Copy link
Copy Markdown
Contributor

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9df4851671

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread codex-rs/app-server-protocol/src/protocol/v2.rs
Comment thread codex-rs/tui/src/bottom_pane/approval_overlay.rs Outdated
@bolinfest
Copy link
Copy Markdown
Collaborator Author

@codex review

Copy link
Copy Markdown
Contributor

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 604c14cfb3

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +1128 to +1130
match value.entries {
Some(entries) => CoreFileSystemPermissions { entries },
None => CoreFileSystemPermissions::from_read_write_roots(value.read, value.write),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Fall back to read/write when entries is empty

Treating any non-None entries value as authoritative drops valid grants when a client sends entries: [] alongside populated legacy read/write fields. In that case this conversion returns an empty CoreFileSystemPermissions, so an approval response that should grant filesystem access is silently downgraded to no filesystem permissions. Because entries is nullable/array in the v2 wire shape, clients can legitimately emit an empty array as a default; this path should either treat empty entries as absent or merge with read/write.

Useful? React with 👍 / 👎.

intersect_permission_paths(requested_file_system.write, granted_file_system.write);
FileSystemPermissions { read, write }
let granted_entries = granted.file_system.unwrap_or_default().entries;
let entries = requested_file_system
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] Preserve narrowing entries when clamping approval grants

This exact-entry intersection is no longer a safe cap now that PermissionProfile can contain semantic narrowing entries. If the request is :root=write plus /tmp/secret.txt=none, and an app-server client responds with only :root=write, the returned profile keeps the root write entry and drops the deny. Because request_permissions_response_from_client_result relies on this helper to clamp client responses to the original request, a partial or buggy client response can grant more filesystem access than Codex requested. The intersection needs to be semantic, or broad grants must be rejected unless the requested carveouts they dominate are preserved.

Comment thread codex-rs/core/src/tools/handlers/mod.rs Outdated
}
_ => false,
};
let session_cwd = session.cwd().await;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] Do not let preapproved requests narrow sticky grants

The new semantic preapproval check can decide that existing sticky grants cover a fresh request, but the effective permissions passed to the runtime still contain both the fresh request and the sticky grant. With a session grant like /workspace=write and a command request like /workspace/docs=read, preapproval succeeds, but the effective profile still contains the more-specific read entry; the runtime policy resolves the child path as read-only, so the command loses write access that the session grant already provided. Sticky grants should continue to widen command permissions, not be revoked by a narrower explicit request unless that is a deliberate deny operation.

Self {
read: value.read,
write: value.write,
match value.entries {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] Do not let empty entries fall back to stale legacy grants

The server can emit mixed permission profiles with both canonical entries and legacy read/write populated. On the response path, though, entries: [] is treated the same as absent entries and falls back to read/write. If a client edits or clears the canonical list but leaves the duplicate legacy fields in place, Codex can grant paths the client no longer meant to grant. Treat a present entries field as authoritative even when empty, or reject/normalize responses where entries and read/write disagree.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants