exec-server: expose arg0 alias root to fs sandbox (#19016)

## Why

The post-merge `rust-ci-full` run for #18999 still failed the Ubuntu
remote `suite::remote_env` sandboxed filesystem tests. That run checked
out merge commit `ddde50c611e4800cb805f243ed3c50bbafe7d011`, so the arg0
guard lifetime fix was present.

The Docker-backed failure had two remaining pieces:

- The sandboxed filesystem helper needs to execute Codex through the
`codex-linux-sandbox` arg0 alias path. The helper sandbox was only
granting read access to the real Codex executable parent, so the alias
parent also has to be visible inside the helper sandbox.
- The remote-env tests were building sandbox contexts with
`FileSystemSandboxContext::new()`, which captures the local test runner
cwd. In the Docker remote exec-server, that host checkout path does not
exist, so spawning the filesystem helper failed with `No such file or
directory` before the helper could process the request.

## What Changed

- Track all helper runtime read roots instead of a single root.
- Add both the real Codex executable parent and the
`codex-linux-sandbox` alias parent to sandbox readable roots.
- Avoid sending an unused local cwd in remote filesystem sandbox
contexts when the permission profile has no cwd-dependent entries.
- Build the Docker remote-env test sandbox contexts with a cwd path that
exists inside the container.
- Add unit coverage for the alias-parent root and remote sandbox cwd
handling.

## Verification

- `cargo test -p codex-exec-server`
- `cargo test -p codex-core
remote_test_env_sandboxed_read_allows_readable_root`
- `just fix -p codex-exec-server`
- `just fix -p codex-core`
This commit is contained in:
Michael Bolin
2026-04-22 14:34:22 -07:00
committed by GitHub
Unverified
parent 16eeeb534a
commit d3dd0d759b
5 changed files with 194 additions and 68 deletions
@@ -317,7 +317,7 @@ async fn read_process_until_closed(
handler: &ExecServerHandler,
process_id: ProcessId,
) -> (String, Option<i32>) {
let deadline = tokio::time::Instant::now() + Duration::from_secs(2);
let deadline = tokio::time::Instant::now() + Duration::from_secs(5);
let mut output = String::new();
let mut exit_code = None;
let mut after_seq = None;
@@ -346,7 +346,7 @@ async fn read_process_until_closed(
after_seq = response.next_seq.checked_sub(1).or(after_seq);
assert!(
tokio::time::Instant::now() < deadline,
"process should close within 2s"
"process should close within 5s"
);
}
}