Files
codex/codex-rs/linux-sandbox/src/bazel_bwrap.rs
Michael Bolin 26f355b67b linux-sandbox: use standalone bundled bwrap (#21255)
**Summary**
- Add `codex-bwrap`, a standalone `bwrap` binary built from the existing
vendored bubblewrap sources.
- Remove the linked vendored bwrap path from `codex-linux-sandbox`;
runtime now prefers system `bwrap` and falls back to bundled
`codex-resources/bwrap`.
- Add bundled SHA-256 verification with missing/all-zero digest as the
dev-mode skip value, then exec the verified file through
`/proc/self/fd`.
- Keep `launcher.rs` focused on choosing and dispatching the preferred
launcher. Bundled lookup, digest verification, and bundled exec now live
in `linux-sandbox/src/bundled_bwrap.rs`; Bazel runfiles lookup lives in
`linux-sandbox/src/bazel_bwrap.rs`; shared argv/fd exec helpers live in
`linux-sandbox/src/exec_util.rs`.
- Teach Bazel tests to surface the Bazel-built `//codex-rs/bwrap:bwrap`
through `CARGO_BIN_EXE_bwrap`; `codex-linux-sandbox` only honors that
fallback in debug Bazel runfiles environments so release/user runtime
lookup stays tied to `codex-resources/bwrap`.
- Allow `codex-exec-server` filesystem helpers to preserve just the
Bazel bwrap/runfiles variables they need in debug Bazel builds, since
those helpers intentionally rebuild a small environment before spawning
`codex-linux-sandbox`.
- Verify the Bazel bwrap target in Linux release CI with a build-only
check. Running `bwrap --version` is too strong for GitHub runners
because bubblewrap still attempts namespace setup there.

**Verification**
- Latest update: `cargo test -p codex-linux-sandbox`
- Latest update: `just fix -p codex-linux-sandbox`
- `cargo check --target x86_64-unknown-linux-gnu -p codex-linux-sandbox`
could not run locally because this macOS machine does not have
`x86_64-linux-gnu-gcc`; GitHub Linux Bazel CI is expected to cover the
Linux-only modules.
- Earlier in this PR: `cargo test -p codex-bwrap`
- Earlier in this PR: `cargo test -p codex-exec-server`
- Earlier in this PR: `cargo check --release -p codex-exec-server`
- Earlier in this PR: `just fix -p codex-linux-sandbox -p
codex-exec-server`
- Earlier in this PR: `bazel test --nobuild
//codex-rs/linux-sandbox:linux-sandbox-all-test
//codex-rs/core:core-all-test
//codex-rs/exec-server:exec-server-file_system-test
//codex-rs/app-server:app-server-all-test` (analysis completed; Bazel
then refuses to run tests under `--nobuild`)
- Earlier in this PR: `bazel build --nobuild //codex-rs/bwrap:bwrap`
- Prior to this update: `just bazel-lock-update`, `just
bazel-lock-check`, and YAML parse check for
`.github/workflows/bazel.yml`


---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/openai/codex/pull/21255).
* #21257
* #21256
* __->__ #21255
2026-05-05 17:14:29 -07:00

69 lines
2.0 KiB
Rust

#[cfg(debug_assertions)]
use std::fs::File;
#[cfg(debug_assertions)]
use std::io::BufRead;
use std::path::PathBuf;
#[cfg(debug_assertions)]
const BAZEL_BWRAP_ENV_VAR: &str = "CARGO_BIN_EXE_bwrap";
#[cfg(debug_assertions)]
pub(crate) fn candidate() -> Option<PathBuf> {
if option_env!("BAZEL_PACKAGE").is_none() || !runfiles_env_present() {
return None;
}
let raw = PathBuf::from(std::env::var_os(BAZEL_BWRAP_ENV_VAR)?);
if raw.is_absolute() {
return Some(raw);
}
resolve_runfile(raw.to_str()?)
}
#[cfg(not(debug_assertions))]
pub(crate) fn candidate() -> Option<PathBuf> {
None
}
#[cfg(debug_assertions)]
fn runfiles_env_present() -> bool {
std::env::var_os("RUNFILES_DIR").is_some()
|| std::env::var_os("TEST_SRCDIR").is_some()
|| std::env::var_os("RUNFILES_MANIFEST_FILE").is_some()
}
#[cfg(debug_assertions)]
fn resolve_runfile(logical_path: &str) -> Option<PathBuf> {
let mut logical_paths = vec![logical_path.to_string()];
if let Ok(workspace) = std::env::var("TEST_WORKSPACE")
&& !workspace.is_empty()
{
logical_paths.push(format!("{workspace}/{logical_path}"));
}
for root_env in ["RUNFILES_DIR", "TEST_SRCDIR"] {
let Some(root) = std::env::var_os(root_env) else {
continue;
};
let root = PathBuf::from(root);
for logical_path in &logical_paths {
let candidate = root.join(logical_path);
if candidate.exists() {
return Some(candidate);
}
}
}
let manifest = PathBuf::from(std::env::var_os("RUNFILES_MANIFEST_FILE")?);
let file = File::open(manifest).ok()?;
for line in std::io::BufReader::new(file).lines().map_while(Result::ok) {
let Some((key, value)) = line.split_once(' ') else {
continue;
};
if logical_paths.iter().any(|logical_path| logical_path == key) {
return Some(PathBuf::from(value));
}
}
None
}