[codex-exec] Enforce add-dir for macOS sandbox#20658
Conversation
6003ea4 to
a74de26
Compare
a74de26 to
f227f2b
Compare
| .map(|profile| HashMap::from([("profile".to_string(), Value::String(profile.clone()))])) | ||
| let mut overrides = HashMap::new(); | ||
| if let Some(profile) = config.active_profile.as_ref() { | ||
| overrides.insert("profile".to_string(), Value::String(profile.clone())); |
There was a problem hiding this comment.
FYI, we are going to be changing how profiles work in #17141.
| overrides.insert( | ||
| "sandbox_workspace_write".to_string(), | ||
| json!({ | ||
| "writable_roots": writable_roots, | ||
| "network_access": network_access, | ||
| "exclude_tmpdir_env_var": exclude_tmpdir_env_var, | ||
| "exclude_slash_tmp": exclude_slash_tmp, | ||
| }), | ||
| ); |
There was a problem hiding this comment.
I feel like it would be ideal if, instead of propagating the use of the legacy sandbox_workspace_write, we injected the appropriate equivalent to something using the [permissions] shape here.
Or, perhaps more appropriately, addressed this at the ConfigBuilder level.
Note config_request_overrides_from_config() was historically created to support a --profile flag, which as I noted, we are trying to redo in a very different way. As such, I would prefer to avoid expanding the role of this function.
| /// with `sandbox` or named `permissions`. | ||
| #[experimental("thread/start.permissionProfile")] | ||
| #[ts(optional = nullable)] | ||
| pub permission_profile: Option<PermissionProfile>, |
There was a problem hiding this comment.
As I noted in a comment on #15977, I do not think we should be exposing this via the app server API: we should only expose profile names. Clients should not be able to specify arbitrary profile values.
de137e2 to
302633f
Compare
302633f to
13656c6
Compare
13656c6 to
d9024bc
Compare
|
I think #22610 made it possible to solve this in a cleaner way by supporting |
|
Closing this because latest main now covers the macOS validation slice this PR was intended to fix. Validated on the AWS macOS VM against main at 249d50a. The Seatbelt harness passed with preflight_pass=5 pass=8 fail=0 skip=0 invalid=0. The key cases passed: normal write in added root, protected .git in added root, and protected metadata read but not write. |
Why
This PR is a user migration fix for the legacy exec sandbox path during the
PermissionProfilemigration.The failing path was:
Then the model shell tool ran from the added root and tried:
macOS Seatbelt returned operation not permitted.
Legacy workspace write added roots are dropped only when
codex execstarts or resumes an app server thread without an active permission profile.That no active profile state is intentional for this legacy path. The local
Confighas the resolved effective permissions, including the added root, but there is no named profile that can be reselected without losing legacy root details. Before this PR,codex execsent onlysandbox = workspace-writeintothread/startandthread/resume. App server rebuilt workspace write permissions from that lossy shape, so the added root was dropped.Change Details
projectRootsrequest fields tothread/startandthread/resume.project_rootsonConfigas the final cwd plus the original--add-dirvalues resolved against that cwd.codex execforwardconfig.project_rootswhen starting or resuming the app server thread.additional_writable_rootsoverride before config builds the thread permissions.Validation
Current pushed head is
351d4995ef671c4ef1169bac7c2dc21b097c94b8.Current head validation:
just fmtcargo check -p codex-thread-manager-samplecargo test -p codex-core add_dir_override_extends_workspace_writable_roots -- --nocapturecargo test -p codex-exec thread_lifecycle_params_include_legacy_sandbox_when_no_active_profile -- --nocapturegit diff --checkEarlier validation on this PR before the Config ownership cleanup:
cargo test -p codex-app-server-protocol -- --nocapturecargo test -p codex-app-server --no-runAWS macOS VM
i-01c31233406f6b2c4, macOS26.4.1build25E253, validated current head351d4995ef671c4ef1169bac7c2dc21b097c94b8:SUMMARY preflight_pass=6 pass=55 fail=0 skip=3 unsupported=0 invalid=0 root=/Users/ec2-user/codex-bugb15632-validation-20260503/macos-seatbelt-cases.jv6Xeg head=351d4995ef671c4ef1169bac7c2dc21b097c94b8 backend=macos-seatbeltjust c execSeatbelt E2E tier:SUMMARY preflight_pass=5 pass=8 fail=0 skip=0 invalid=0 root=/Users/ec2-user/codex-bugb15632-validation-20260503/just-c-exec-e2e-cases.MeIPIc head=351d4995ef671c4ef1169bac7c2dc21b097c94b8 backend=just-c-exec-macos-seatbelt