mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
fix(linux-sandbox): avoid panic on bwrap build failures (#21127)
## Summary - Propagate Linux bubblewrap argument-construction failures instead of panicking in the helper - Keep mutable-symlink carveouts fail-closed while reporting them as ordinary sandbox build failures - Add regression coverage for a protected `.codex` symlink inside a writable workspace root ## Root cause Linux bubblewrap intentionally rejects read-only carveouts that cross a symlink the sandboxed process can still rewrite. That is the correct security behavior for protected metadata paths such as `.codex`. The bug was one layer higher: `linux_run_main` treated the expected build failure as impossible and panicked while constructing the bubblewrap argv. For issue #20716, that turned a normal fail-closed sandbox outcome into a noisy panic in the transcript. ## User impact Users with a project-local `.codex` symlink inside a writable workspace still get the conservative sandbox decision, but they no longer see a Rust panic for that condition. The helper now exits with the concise sandbox-build error so the normal denial / escalation path can handle it. Fixes #20716
This commit is contained in:
@@ -587,6 +587,59 @@ async fn sandbox_blocks_codex_symlink_replacement_attack() {
|
||||
assert_ne!(codex_output.exit_code, 0);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn sandbox_reports_codex_symlink_build_failure_without_panicking() {
|
||||
if should_skip_bwrap_tests().await {
|
||||
eprintln!("skipping bwrap test: bwrap sandbox prerequisites are unavailable");
|
||||
return;
|
||||
}
|
||||
|
||||
use std::os::unix::fs::symlink;
|
||||
|
||||
let tmpdir = tempfile::tempdir().expect("tempdir");
|
||||
let decoy = tmpdir.path().join("decoy-codex");
|
||||
std::fs::create_dir_all(&decoy).expect("create decoy dir");
|
||||
|
||||
let dot_codex = tmpdir.path().join(".codex");
|
||||
symlink(&decoy, &dot_codex).expect("create .codex symlink");
|
||||
|
||||
let output = match run_cmd_result_with_writable_roots(
|
||||
&["bash", "-lc", "true"],
|
||||
&[tmpdir.path().to_path_buf()],
|
||||
LONG_TIMEOUT_MS,
|
||||
/*use_legacy_landlock*/ false,
|
||||
/*network_access*/ true,
|
||||
)
|
||||
.await
|
||||
{
|
||||
Err(CodexErr::Sandbox(SandboxErr::Denied { output, .. })) => *output,
|
||||
result => panic!(".codex symlink build failure should deny: {result:?}"),
|
||||
};
|
||||
|
||||
assert_eq!(output.exit_code, 1);
|
||||
assert!(
|
||||
output
|
||||
.stderr
|
||||
.text
|
||||
.contains("error building bubblewrap command:"),
|
||||
"stderr: {}",
|
||||
output.stderr.text
|
||||
);
|
||||
assert!(
|
||||
output
|
||||
.stderr
|
||||
.text
|
||||
.contains("cannot enforce sandbox read-only path"),
|
||||
"stderr: {}",
|
||||
output.stderr.text
|
||||
);
|
||||
assert!(
|
||||
!output.stderr.text.contains("panicked at"),
|
||||
"stderr: {}",
|
||||
output.stderr.text
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn sandbox_keeps_parent_repo_discovery_while_blocking_child_metadata() {
|
||||
if should_skip_bwrap_tests().await {
|
||||
|
||||
Reference in New Issue
Block a user