sandbox-agent-santiago-afonso

内容来源:README.md(说明文档) · 原始地址 · 查看安装指南

原始内容

sandbox-agent

A Podman wrapper that runs agent CLIs (primarily codex, but also copilot, opencode, and pi) inside a container.

For codex, it always uses:

  • --search (web search tool availability)
  • --config web_search=live|cached|disabled (defaults to cached, or uses host ~/.codex/config.toml if set)

Networking is enabled (full egress).

Quick start

1) Build an image

You need an image that includes codex, git, bash, and uv (plus a Python runtime; this image uses uv-managed Python by default, and exposes it as python3 in the container). Use Containerfile:

podman build -t localhost/sandbox-agent:latest -f Containerfile .

Or use the Makefile (also installs the wrapper):

make install

If you're on a corporate network with an npm mirror, override the registry:

make install NPM_REGISTRY=https://your-registry.example.com/

If TLS is intercepted (transparent proxy / self-signed in chain), pass a corporate CA file:

make install EXTRA_CA_CERT_PATH=$HOME/.local/share/machine-setup/certs/wbg-corp-ca-bundle.pem

The build accepts a single PEM cert, a PEM bundle, or a single DER cert.

If EXTRA_CA_CERT_PATH is not set, the Makefile auto-detects WBG CA material only on the WBG laptop hostname (PCACL-G7MKN94) by checking:

  • bin/wbg-ca-helper corp-bundle-path (preferred; generated local bundle), then
  • ~/.local/share/machine-setup/certs/wbg-corp-ca-bundle.pem, then
  • ~/wbg-cloud-root-ca.pem or ../../wbg-cloud-root-ca.pem, then
  • ~/wbg_root_ca_g2.cer or ../../wbg_root_ca_g2.cer as a legacy fallback.

These cert files are not stored in the repo; they are local machine files and should not be committed.

You can also override bundled tool versions:

make install CODEX_NPM_PKG=@openai/codex@latest OPENCODE_VERSION=latest \
  MQ_VERSION=0.5.9 MQ_TARGET=x86_64-unknown-linux-gnu \
  TYPST_VERSION=0.14.2 TYPST_TARGET=x86_64-unknown-linux-musl

mq is installed from its GitHub release assets and verified against the upstream checksums.txt. If you override MQ_TARGET, make sure the selected MQ_VERSION publishes a matching release artifact.

Override the default uv-managed Python version:

make install UV_DEFAULT_PYTHON=3.14

You can also override the bundled uv binary version (rarely needed):

make install UV_VERSION=0.9.21

If you want a smaller build (skip Playwright’s bundled browser download), set:

make install INSTALL_PLAYWRIGHT_BROWSERS=0

2) Install the wrapper

install -m 0755 ./sandbox-agent ~/.local/bin/sandbox-agent
install -m 0755 ./sandbox-agent-codex ~/.local/bin/sandbox-agent-codex
install -m 0755 ./sandbox-agent-copilot ~/.local/bin/sandbox-agent-copilot
install -m 0755 ./sandbox-agent-opencode ~/.local/bin/sandbox-agent-opencode
install -m 0755 ./sandbox-agent-pi ~/.local/bin/sandbox-agent-pi

3) (Optional) Configure mounts

Create ~/.config/sandbox-agent/config.sh:

CODEX_CONTAINER_SANDBOX_IMAGE="localhost/sandbox-agent:latest"

# Optional: force an OCI runtime (useful on some WSL/work setups).
# CODEX_CONTAINER_SANDBOX_PODMAN_RUNTIME="runc"

# Optional: override DNS servers used inside the container.
# Default behavior is to inherit host/Podman DNS.
# Enable override explicitly:
# CODEX_CONTAINER_SANDBOX_DISABLE_DNS_OVERRIDE=0
# Or override the server list (in order):
# CODEX_CONTAINER_SANDBOX_DNS_SERVERS=(45.90.28.212 45.90.30.212 1.1.1.1 8.8.8.8)
#
# Note: When DNS override is enabled, the wrapper bind-mounts a generated
# /etc/resolv.conf into the container to bypass Podman DNS forwarders (often a
# 169.254.x.x hop).

# Mount helper tools read-only (mapped under /home/codex/...)
CODEX_CONTAINER_SANDBOX_RO_MOUNTS=(
  "$HOME/.local/bin"
  "$HOME/bin"
)

# Persist caches if needed
CODEX_CONTAINER_SANDBOX_RW_MOUNTS=(
  "$HOME/.cache/uv"
  "$HOME/tmp"
)

# Optional: add host env vars to pass through into the container.
# Defaults already include common LLM providers + AWS Bedrock credentials.
# CODEX_CONTAINER_SANDBOX_ENV_PASSTHROUGH+=(MY_EXTRA_API_KEY)
#
# Optional: disable default passthrough list, then define an explicit allowlist.
# CODEX_CONTAINER_SANDBOX_DISABLE_DEFAULT_ENV_PASSTHROUGH=1
# CODEX_CONTAINER_SANDBOX_ENV_PASSTHROUGH=(
#   GEMINI_API_KEY
#   GOOGLE_API_KEY
# )
#
# Optional: override/disable host OpenCode agents mount.
# CODEX_CONTAINER_SANDBOX_OPENCODE_AGENTS_DIR="$HOME/.config/opencode/agents"
# CODEX_CONTAINER_SANDBOX_DISABLE_OPENCODE_AGENTS_MOUNT=1

Usage

Default: zsh shell in container

sandbox-agent

Codex (full network)

sandbox-agent codex exec "Summarize the repo"

OpenCode (full network)

sandbox-agent opencode agent list

Instruction-source dry run (recommended)

Prints effective global/project AGENTS sources and mount targets without launching the container:

sandbox-agent --dry-run-instructions codex exec "noop"

Project AGENTS modes for codex exec

For sandbox-agent codex exec, project AGENTS behavior is explicit and mode-driven:

  • suppress (default): do not mount project AGENTS.md
  • repo: mount repo-root AGENTS.md
  • replace: mount a custom project AGENTS file
  • concat: compose custom + repo (custom first), then mount combined file

Examples:

# Use repo AGENTS.md
sandbox-agent --project-agents-mode repo codex exec "..."

# Replace project AGENTS.md with a custom file
sandbox-agent --project-agents-mode replace --project-agents-file ~/my-project-agents.md codex exec "..."

# Concatenate custom + repo AGENTS
sandbox-agent --project-agents-mode concat --project-agents-file ~/.codex/AGENTS.md codex exec "..."

You can also pin an explicit global AGENTS file for codex exec:

sandbox-agent --global-agents-file ~/machine-setup/tools/sandbox-agent/SANDBOXED-AGENT-AGENTS.md codex exec "..."

Single preset to combine sandbox global AGENTS + host ~/.codex/AGENTS.md (as project concat):

sandbox-agent --instruction-profile host-plus-sandbox codex exec "..."

Pi (pi-mono coding agent)

sandbox-agent pi

pi is available in the image, but sandbox-agent does not auto-install pi plugins/packages. Install only what you need in your ~/.pi/ state.

Makefile helpers

From the repo root:

make image
make selftest
make selftest-instructions
make pii-scan
make validate-docs

Self-test (network + mount isolation)

Runs seven checks:

  1. Container has internet connectivity.
  2. Playwright + Chromium are usable.
  3. Codex + OpenCode CLIs are available in-container.
  4. Host files outside the workspace are not visible by default.
  5. An explicitly mounted host directory is readable and writable (RW mount).
  6. OpenCode agents mount wiring is visible in dry-run, mounted read-only when a host source exists, and --rw overlaps with ~/.agents are rejected.
  7. Instruction-source flag matrix passes (scripts/test_instruction_flags.sh).
./selftest.sh

Shell inside container

sandbox-agent --shell

Debug the podman command

CODEX_CONTAINER_SANDBOX_DEBUG=1 sandbox-agent codex exec "hello"

Hide the printed codex ... command

By default the wrapper prints the computed codex ... command (to stderr) before starting. Disable with:

sandbox-agent --no-print-codex-cmd codex exec "hello"

Git commit identity

To avoid git commit failing with “Author identity unknown”, the wrapper will (by default) copy user.name / user.email from the host git config into a persistent container-global gitconfig under CODEX_HOME, and set GIT_CONFIG_GLOBAL accordingly.

Override (or set explicitly if host identity is not set):

CODEX_CONTAINER_SANDBOX_GIT_NAME="Your Name" \
CODEX_CONTAINER_SANDBOX_GIT_EMAIL="you@domain" \
  sandbox-agent ...

Disable:

CODEX_CONTAINER_SANDBOX_DISABLE_GIT_IDENTITY_SYNC=1 sandbox-agent ...

Mount behavior

  • If you run inside a git repo, the repo root is mounted read-write.
  • The container working directory is set to your original $PWD inside that mount.
  • For codex exec, global AGENTS is mounted from canonical SANDBOXED-AGENT-AGENTS.md to container ~/.codex/AGENTS.md (or from --global-agents-file when provided).
  • Extra mounts under $HOME are mapped to the same relative path under /home/codex.
  • XDG_CACHE_HOME is set to $CODEX_HOME/cache so tools like uv have a writable cache by default.
  • If host OpenCode agents are discoverable, they are mounted read-only to ~/.config/opencode/agents.
  • Pi state in the container lives under ~/.pi/, backed by a wrapper-managed host directory: ~/.local/state/sandbox-agent/pi (disable with CODEX_CONTAINER_SANDBOX_DISABLE_PI_MOUNT=1).
  • If host ~/.pi/agent exists, it is mounted read-only into the container at ~/.pi-host/agent so you can reuse host extensions/prompts without allowing in-container mutation (disable with CODEX_CONTAINER_SANDBOX_DISABLE_PI_HOST_AGENT_MOUNT=1).
  • sandbox-agent does not seed pi harness plugins into ~/.pi/agent/settings.json.
  • Any mounts derived from ~/.agents are read-only by design.
  • If ~/.agents resolves into the mounted workspace tree, sandbox-agent adds a read-only submount at that workspace path so the repo bind mount cannot make it writable.
  • sandbox-agent refuses explicit --rw mounts that overlap ~/.agents.

Auth

Codex credentials live in CODEX_HOME (~/.local/state/sandbox-agent by default). Login once inside the container:

sandbox-agent --shell
codex login

Reuse host auth.json (optional)

If you already have a working host login (for example ~/.codex/auth.json), you can mount it into the container so codex doesn't prompt for login again:

  • Auto-detects and mounts ~/.codex/auth.json if it exists.
  • Override the path with CODEX_CONTAINER_SANDBOX_AUTH_FILE=/path/to/auth.json.
  • Disable mounting entirely with CODEX_CONTAINER_SANDBOX_DISABLE_AUTH_MOUNT=1.
  • Control mount mode (default ro) with CODEX_CONTAINER_SANDBOX_AUTH_MOUNT_MODE=ro|rw.

Reuse host skills and Pi customizations (optional)

To keep Codex skills consistent with your host setup, the wrapper can mount:

  • ~/.agents/skills (preferred) or ~/.codex/skills (fallback) -> $CODEX_HOME/skills (read-only)

Controls:

  • Override paths:
    • CODEX_CONTAINER_SANDBOX_SKILLS_DIR=/path/to/skills
  • Disable:
    • CODEX_CONTAINER_SANDBOX_DISABLE_SKILLS_MOUNT=1

Pi prompt templates ride through the existing read-only ~/.pi/agent mount. When setup.sh wires ~/.pi/agent/prompts to .agents/generated/pi/prompts, the container sees the same templates at ~/.pi-host/agent/prompts without any separate Codex prompt mount.

Reuse host OpenCode agents (optional)

To keep OpenCode role definitions consistent with your host setup, the wrapper can mount:

  • ~/.config/opencode/agents (preferred)
  • ~/.agents/subagents/generated/opencode/agents (fallback)
  • <workspace>/.agents/subagents/generated/opencode/agents (repo-local fallback)

All OpenCode agents mounts are read-only and target:

  • ~/.config/opencode/agents inside the container

Controls:

  • Override path:
    • CODEX_CONTAINER_SANDBOX_OPENCODE_AGENTS_DIR=/path/to/agents
  • Disable:
    • CODEX_CONTAINER_SANDBOX_DISABLE_OPENCODE_AGENTS_MOUNT=1

LLM env passthrough

The wrapper forwards a default allowlist of provider credential environment variables from host to container (only when each variable is present on host):

  • OPENAI_API_KEY
  • ANTHROPIC_API_KEY
  • GEMINI_API_KEY
  • GOOGLE_API_KEY
  • GOOGLE_GENAI_API_KEY
  • AZURE_OPENAI_API_KEY
  • AZURE_OPENAI_ENDPOINT
  • ELEVENLABS_API_KEY
  • MISTRAL_API_KEY
  • COHERE_API_KEY
  • GROQ_API_KEY
  • PERPLEXITY_API_KEY
  • TOGETHER_API_KEY
  • FIREWORKS_API_KEY
  • OPENROUTER_API_KEY
  • XAI_API_KEY
  • DEEPSEEK_API_KEY
  • CEREBRAS_API_KEY
  • AWS_ACCESS_KEY_ID
  • AWS_SECRET_ACCESS_KEY
  • AWS_SESSION_TOKEN
  • AWS_REGION
  • AWS_DEFAULT_REGION
  • AWS_PROFILE

Customization:

  • Add extra vars in ~/.config/sandbox-agent/config.sh:
    • CODEX_CONTAINER_SANDBOX_ENV_PASSTHROUGH+=(MY_EXTRA_API_KEY)
  • Replace defaults with your own explicit list:
    • CODEX_CONTAINER_SANDBOX_DISABLE_DEFAULT_ENV_PASSTHROUGH=1
    • CODEX_CONTAINER_SANDBOX_ENV_PASSTHROUGH=(VAR_A VAR_B)

Reuse host helper CLIs (read-pdf)

If you have read-pdf installed on the host at ~/.local/bin/read-pdf, the wrapper will mount that executable (and its helper scripts like read_pdf_page_candidates.py) read-only into the container (without mounting the entire ~/.local/bin directory) so it is available on the container $PATH.

Disable with:

CODEX_CONTAINER_SANDBOX_DISABLE_LOCAL_BIN_MOUNT=1 sandbox-agent ...

Built-in tools (image is self-sufficient)

The image ships with a few common “skills dependencies” so you don’t need host mounts:

  • codex
  • opencode
  • copilot
  • pi
  • imagemagick (convert, identify) for image-crop
  • poppler-utils (pdfinfo, pdftoppm) for read-pdf --as-images
  • markitdown for read-webpage-content-as-markdown and read-pdf --as-text-fast
  • pandoc
  • mq
  • typst
  • chromium + playwright (JS/client-rendered pages)

Reuse host CLIs (optional; for extra tools/versions)

If you install CLIs on the host via:

  • uv tool install ... (often creates symlinks under ~/.local/bin pointing at ~/.local/share/uv/tools/...)

the wrapper can mount the needed host directories read-only so those tools work inside the container.

Defaults (best-effort, only when detected):

  • Mount ~/.local/share/uv/tools read-only when ttok is detected as a uv tool install.
  • Also mount ~/.local/share/uv/python read-only (needed for uv tool shebang interpreters) when present.
  • Mount host ~/.opencode/bin/opencode read-only when present (fallback path; in-image /usr/local/bin/opencode remains preferred).

Disable:

CODEX_CONTAINER_SANDBOX_DISABLE_UV_TOOLS_MOUNT=1 sandbox-agent ...
CODEX_CONTAINER_SANDBOX_DISABLE_UV_PYTHON_MOUNT=1 sandbox-agent ...

Security note

This wrapper is about filesystem isolation (mount boundaries), not egress safety. Because this runs full yolo with full networking, the agent can exfiltrate anything it can read inside the container (including anything you mount, and CODEX_HOME/auth.json).