permissions: make legacy profile conversion cwd-free (#19414)

## Why

The profile conversion path still required a `cwd` even when it was only
translating a legacy `SandboxPolicy` into a `PermissionProfile`. That
made profile producers invent an ambient `cwd`, which is exactly the
anchoring we are trying to remove from permission-profile data. A legacy
workspace-write policy can be represented symbolically instead: `:cwd =
write` plus read-only `:project_roots` metadata subpaths.

This PR creates that cwd-free base so the rest of the stack can stop
threading cwd through profile construction. Callers that actually need a
concrete runtime filesystem policy for a specific cwd still have an
explicitly named cwd-bound conversion.

## What Changed

- `PermissionProfile::from_legacy_sandbox_policy` now takes only
`&SandboxPolicy`.
- `FileSystemSandboxPolicy::from_legacy_sandbox_policy` is now the
symbolic, cwd-free projection for profiles.
- The old concrete projection is retained as
`FileSystemSandboxPolicy::from_legacy_sandbox_policy_for_cwd` for
runtime/boundary code that must materialize legacy cwd behavior.
- Workspace-write profiles preserve `CurrentWorkingDirectory` and
`ProjectRoots` special entries instead of materializing cwd into
absolute paths.

## Verification

- `cargo check -p codex-protocol -p codex-core -p
codex-app-server-protocol -p codex-app-server -p codex-exec -p
codex-exec-server -p codex-tui -p codex-sandboxing -p
codex-linux-sandbox -p codex-analytics --tests`
- `just fix -p codex-protocol -p codex-core -p codex-app-server-protocol
-p codex-app-server -p codex-exec -p codex-exec-server -p codex-tui -p
codex-sandboxing -p codex-linux-sandbox -p codex-analytics`




---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/openai/codex/pull/19414).
* #19395
* #19394
* #19393
* #19392
* #19391
* __->__ #19414
This commit is contained in:
Michael Bolin
2026-04-24 13:42:05 -07:00
committed by GitHub
Unverified
parent 7262c0c450
commit 13e0ec1614
29 changed files with 281 additions and 139 deletions
@@ -2291,7 +2291,7 @@ impl CodexMessageProcessor {
match self.config.permissions.sandbox_policy.can_set(&policy) {
Ok(()) => {
let file_system_sandbox_policy =
codex_protocol::permissions::FileSystemSandboxPolicy::from_legacy_sandbox_policy(&policy, &sandbox_cwd);
codex_protocol::permissions::FileSystemSandboxPolicy::from_legacy_sandbox_policy_for_cwd(&policy, &sandbox_cwd);
let network_sandbox_policy =
codex_protocol::permissions::NetworkSandboxPolicy::from(&policy);
(policy, file_system_sandbox_policy, network_sandbox_policy)
@@ -10545,18 +10545,15 @@ mod tests {
#[test]
fn thread_response_permission_profile_preserves_enforcement() {
let cwd = test_path_buf("/tmp").abs();
let full_access_profile =
codex_protocol::models::PermissionProfile::from_legacy_sandbox_policy(
&SandboxPolicy::DangerFullAccess,
cwd.as_path(),
);
let external_profile =
codex_protocol::models::PermissionProfile::from_legacy_sandbox_policy(
&SandboxPolicy::ExternalSandbox {
network_access: codex_protocol::protocol::NetworkAccess::Restricted,
},
cwd.as_path(),
);
assert_eq!(
@@ -10575,17 +10572,14 @@ mod tests {
let full_access_profile =
codex_protocol::models::PermissionProfile::from_legacy_sandbox_policy(
&SandboxPolicy::DangerFullAccess,
cwd.as_path(),
);
let workspace_write_profile =
codex_protocol::models::PermissionProfile::from_legacy_sandbox_policy(
&SandboxPolicy::new_workspace_write_policy(),
cwd.as_path(),
);
let read_only_profile =
codex_protocol::models::PermissionProfile::from_legacy_sandbox_policy(
&SandboxPolicy::new_read_only_policy(),
cwd.as_path(),
);
assert!(requested_permissions_trust_project(
@@ -10797,7 +10791,6 @@ mod tests {
permission_profile:
codex_protocol::models::PermissionProfile::from_legacy_sandbox_policy(
&codex_protocol::protocol::SandboxPolicy::DangerFullAccess,
cwd.as_path(),
),
cwd,
ephemeral: false,