To support Bazelification in https://github.com/openai/codex/pull/8875, this PR introduces a new `find_resource!` macro that we use in place of our existing logic in tests that looks for resources relative to the compile-time `CARGO_MANIFEST_DIR` env var. To make this work, we plan to add the following to all `rust_library()` and `rust_test()` Bazel rules in the project: ``` rustc_env = { "BAZEL_PACKAGE": native.package_name(), }, ``` Our new `find_resource!` macro reads this value via `option_env!("BAZEL_PACKAGE")` so that the Bazel package _of the code using `find_resource!`_ is injected into the code expanded from the macro. (If `find_resource()` were a function, then `option_env!("BAZEL_PACKAGE")` would always be `codex-rs/utils/cargo-bin`, which is not what we want.) Note we only consider the `BAZEL_PACKAGE` value when the `RUNFILES_DIR` environment variable is set at runtime, indicating that the test is being run by Bazel. In this case, we have to concatenate the runtime `RUNFILES_DIR` with the compile-time `BAZEL_PACKAGE` value to build the path to the resource. In testing this change, I discovered one funky edge case in `codex-rs/exec-server/tests/common/lib.rs` where we have to _normalize_ (but not canonicalize!) the result from `find_resource!` because the path contains a `common/..` component that does not exist on disk when the test is run under Bazel, so it must be semantically normalized using the [`path-absolutize`](https://crates.io/crates/path-absolutize) crate before it is passed to `dotslash fetch`. Because this new behavior may be non-obvious, this PR also updates `AGENTS.md` to make humans/Codex aware that this API is preferred.
codex-exec-server
This crate contains the code for two executables:
codex-exec-mcp-serveris an MCP server that provides a tool namedshellthat runs a shell command inside a sandboxed instance of Bash. Every resultingexecve(2)call made within Bash is intercepted and run via the executable defined by theBASH_EXEC_WRAPPERenvironment variable within the Bash process. In practice,BASH_EXEC_WRAPPERis set tocodex-execve-wrapper.codex-execve-wrapperis the executable that takes the arguments to theexecve(2)call and "escalates" it to the MCP server via a shared file descriptor (specified by theCODEX_ESCALATE_SOCKETenvironment variable) for consideration. Based on the Codex.rules, the MCP server replies with one of:Run:codex-execve-wrappershould invokeexecve(2)on itself to run the original command within BashEscalate: forward the file descriptors of the current process to the MCP server so the command can be run faithfully outside the sandbox. Because the MCP server will have the original FDs forstdoutandstderr, it can write those directly. When the process completes, the MCP server forwards the exit code tocodex-execve-wrapperso that it exits in a consistent manner.Deny: the MCP server has declared the proposed command to be "forbidden," socodex-execve-wrapperwill print an error tostderrand exit with1.
Patched Bash
We carry a small patch to execute_cmd.c (see patches/bash-exec-wrapper.patch) that adds support for BASH_EXEC_WRAPPER. The original commit message is “add support for BASH_EXEC_WRAPPER” and the patch applies cleanly to a8a1c2fac029404d3f42cd39f5a20f24b6e4fe4b from https://github.com/bminor/bash. To rebuild manually:
git clone https://github.com/bminor/bash
git checkout a8a1c2fac029404d3f42cd39f5a20f24b6e4fe4b
git apply /path/to/patches/bash-exec-wrapper.patch
./configure --without-bash-malloc
make -j"$(nproc)"
Release workflow
.github/workflows/shell-tool-mcp.yml builds the Rust binaries, compiles the patched Bash variants, assembles the vendor/ tree, and creates codex-shell-tool-mcp-npm-<version>.tgz for inclusion in the Rust GitHub Release. When the version is a stable or alpha tag, the workflow also publishes the tarball to npm using OIDC. The workflow is invoked from rust-release.yml so the package ships alongside other Codex artifacts.