mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
c65cfeab14
## tl;dr
Inject a `CODEX_PERMISSION_PROFILE` environment variable with the name
of the current permission profile when invoking a shell tool.
## Why
Shell tool owners may need to launch nested commands under the same
named permission profile, including through `codex sandbox -P PROFILE
--include-managed-config`. Until now, child processes could observe
sandbox and network metadata but could not identify the active named
permission profile.
The `--include-managed-config` flag is essential when a helper
reconstructs the sandbox from a profile name: it ensures the nested
sandbox also loads managed enterprise requirements. Without it, using
the inherited profile could unintentionally create a sandbox that does
not enforce the organization's managed restrictions.
The new environment value is intentionally informational and **must not
be treated as trusted input**. Any process in the ancestry can overwrite
an environment variable, so a consumer that passes this value to `codex
sandbox -P` must first validate it against the profiles that helper is
authorized to use.
## Example Use Case
Suppose an organization provides a trusted `remote-bash` wrapper that
lets Codex run a command on an approved build host. The local shell
command uses the named `:workspace` permission profile:
```toml
default_permissions = ":workspace"
```
The command exposed to the model is a small zsh wrapper. It deliberately
delegates with `exec`, preserving the original arguments and process
environment:
```zsh
#!/usr/bin/env zsh
exec /opt/codex-tools/remote_bash.py "$@"
```
The model invokes the public wrapper, not its Python implementation:
```sh
/opt/codex-tools/remote-bash \
--host builder.example.com \
-- printf '%s' 'hello world'
```
Only the inner implementation is authorized to escape the local sandbox:
```starlark
prefix_rule(
pattern=["/opt/codex-tools/remote_bash.py"],
decision="allow",
)
```
With zsh-fork, execution begins with `remote-bash` inside the
`:workspace` sandbox. When the wrapper calls `exec`, the exact prefix
rule matches `remote_bash.py`, so that inner script is restarted
unsandboxed. The escalated process inherits:
```text
CODEX_PERMISSION_PROFILE=:workspace
```
Inheritance does not make the value trustworthy. `remote_bash.py`
independently allowlists both the remote host and the permission profile
before using either value. In particular, a forged value such as
`:danger-full-access` is rejected before it can reach `codex sandbox
-P`:
```python
import argparse
import os
import shlex
import sys
ALLOWED_HOSTS = {"builder.example.com"}
ALLOWED_PROFILES = {":workspace"}
parser = argparse.ArgumentParser()
parser.add_argument("--host", required=True)
separator = sys.argv.index("--")
args = parser.parse_args(sys.argv[1:separator])
command = sys.argv[separator + 1:]
if args.host not in ALLOWED_HOSTS:
parser.error("host is not allowlisted")
if not command:
parser.error("the remote command must not be empty")
profile = os.environ.get("CODEX_PERMISSION_PROFILE")
if not profile:
raise SystemExit("CODEX_PERMISSION_PROFILE must not be empty")
if profile not in ALLOWED_PROFILES:
raise SystemExit("CODEX_PERMISSION_PROFILE is not allowlisted")
remote_command = shlex.join(command)
sandbox_command = shlex.join([
"codex", "sandbox", "-P", profile,
"--include-managed-config", "--",
"bash", "-lc", remote_command,
])
print(shlex.join(["ssh", args.host, sandbox_command]))
```
This builds each command layer as an argument vector and uses
`shlex.join()` at the boundary, rather than interpolating untrusted
shell text. After validation and parsing, the nested command has this
structure:
```text
ssh argv:
["ssh", "builder.example.com", SANDBOX_COMMAND]
SANDBOX_COMMAND argv:
["codex", "sandbox", "-P", ":workspace",
"--include-managed-config", "--",
"bash", "-lc", "printf %s 'hello world'"]
bash -lc payload argv:
["printf", "%s", "hello world"]
```
A production implementation could execute that SSH command. The
integration fixture prints it and parses the result back into arguments,
verifying the complete flow:
```text
model invokes outer wrapper
-> zsh-fork starts wrapper under :workspace
-> wrapper execs allowlisted Python script
-> prefix rule restarts Python script unsandboxed
-> Python script inherits CODEX_PERMISSION_PROFILE=:workspace
-> Python script verifies :workspace is allowlisted
-> remote command runs codex sandbox -P :workspace
with --include-managed-config
-> nested sandbox honors managed enterprise requirements
```
This gives the trusted helper access to resources outside the local
sandbox—such as SSH credentials—while ensuring that it can select only
an explicitly authorized profile and that work on the remote host
remains subject to the organization's managed requirements.
## What changed
- Inject `CODEX_PERMISSION_PROFILE` after shell environment policy
evaluation so the active profile wins over inherited or configured stale
values.
- Apply the variable to both `shell_command` and unified `exec_command`,
including local, zsh-fork, and remote exec-server paths.
- Remove stale values when the session has no active named profile.
- Preserve the current profile value when loading a shell snapshot so a
parent snapshot cannot restore an older profile.
## Testing
- Added classic-shell integration coverage proving an exact prefix rule
can run a `require_escalated` script outside the `:workspace` sandbox
while preserving `CODEX_PERMISSION_PROFILE=:workspace`.
- Added zsh-fork integration coverage in which the model invokes an
outer zsh wrapper, an inner allowlisted `remote_bash.py` runs
unsandboxed, and its printed SSH command reconstructs the inherited
`:workspace` sandbox with `--include-managed-config` while preserving
every argument after `--`.
- The example helper treats `CODEX_PERMISSION_PROFILE` as untrusted and
validates it against `ALLOWED_PROFILES` before constructing the nested
command.
- Assert that the reconstructed sandbox command includes
`--include-managed-config` so nested use of the inherited profile cannot
bypass managed enterprise requirements.
- Added coverage for overriding and removing stale profile values.
- Verified `shell_command` receives the selected active profile.
- Added shell snapshot coverage using `printenv
CODEX_PERMISSION_PROFILE`.
c65cfeab14
·
2026-06-25 19:00:23 +00:00
History