Bug: MCP safe-output tools not invoked when Codex runs inside AWF chroot on self-hosted runners
Summary
When using the Codex engine with the AWF sandbox enabled on self-hosted runners running as root, Codex never invokes MCP safe-output tools (add_comment, add_labels, noop). The workflow completes successfully with exit code 0 but no comment or label is posted to the PR.
Evidence
- gh-aw v0.58.0 +
sandbox.agent: false (no AWF chroot): Codex runs as root on the host → reads MCP config → calls add_comment → works correctly
- gh-aw v0.60.0 + sandbox enabled (AWF chroot): Codex runs as
ec2-user (UID 1000) inside chroot → can't read root-owned MCP config → MCP tools invisible → no tool calls → no output
Root Cause
The AWF chroot drops privileges to a non-root host user (e.g. ec2-user, UID 1000) before executing Codex. However, the following files are created by root during compiler-generated setup steps and are not readable by the chroot user:
-
/tmp/gh-aw/mcp-config/config.toml (GH_AW_MCP_CONFIG) — Codex reads this to discover MCP servers. When unreadable, Codex has no knowledge of add_comment/add_labels/noop tools and falls back to built-in tools only (exec_command, file reads, etc.).
-
/opt/gh-aw/safeoutputs/outputs.jsonl (GH_AW_SAFE_OUTPUTS) — Even if Codex could call tools, the output file path is under root-owned /opt/gh-aw/.
These files are created after any user-defined steps: run (e.g. Write Safe Outputs Config, Start Safe Outputs MCP HTTP Server), so workflow-level chmod workarounds cannot fix them.
The MCP gateway tools/list responses seen in gateway logs come from the gateway's own startup (running as root on the host), not from Codex inside the chroot. Codex inside the chroot never connects to the MCP gateway because it cannot read the config file.
Why This Only Affects Self-Hosted Runners
On GitHub-hosted runners, the runner user has broader filesystem permissions. On self-hosted runners configured to run as root (common pattern for AWS EC2 runners), the AWF chroot drops to a non-root user that cannot read root-owned files under /tmp/gh-aw/ and /opt/gh-aw/.
Observed Symptoms
# MCP gateway ingestion step:
Error reading agent output file: ENOENT: no such file or directory, open '/tmp/gh-aw/agent_output.json'
No agent output available - nothing to process
# Safe outputs step:
Output file does not exist: /opt/gh-aw/safeoutputs/outputs.jsonl
No agent output available - nothing to process
Workflow job exits with code 0 (success) but the conclusion job logs:
No no-op message found, skipping
Agentic Implementation Plan
File to modify: containers/agent/entrypoint.sh
Before the capsh --user=${HOST_USER} privilege drop, add a chmod to make gh-aw files accessible to the chroot user. Insert after the DNS configuration section (~line 430) and before the chroot /host /bin/bash -c "..." block:
# Ensure gh-aw temp files are accessible by the chroot user (UID: )
# These files are created by root during setup steps and must be readable
# by the non-root chroot user for MCP config discovery and safe-output writing.
echo "[entrypoint] Setting gh-aw directory permissions for chroot user..."
chmod -R a+rX /host/tmp/gh-aw 2>/dev/null || true
chmod -R a+rwX /host/tmp/gh-aw/mcp-config 2>/dev/null || true
chmod -R a+rwX /host/opt/gh-aw/safeoutputs 2>/dev/null || true
This mirrors how the entrypoint already handles awfuser home directory ownership:
chown -R awfuser:awfuser /home/awfuser 2>/dev/null || true
Tests to add in src/docker-manager.test.ts or a new integration test:
- Verify that a workflow using Codex engine on a self-hosted runner (simulated with a non-root chroot user) can invoke MCP safe-output tools after the permission fix
Environment
- gh-aw CLI: v0.60.0
- AWF: v0.24.2
- Engine: codex (
@openai/codex v0.115.0)
- Model: gpt-5.3-codex (via internal OpenAI-compatible LLM router using
--openai-api-target)
- Runner: Self-hosted (Amazon Linux 2023), runner service runs as
root, AWF chroot drops to ec2-user (UID 1000)
Related
Bug: MCP safe-output tools not invoked when Codex runs inside AWF chroot on self-hosted runners
Summary
When using the Codex engine with the AWF sandbox enabled on self-hosted runners running as root, Codex never invokes MCP safe-output tools (
add_comment,add_labels,noop). The workflow completes successfully with exit code 0 but no comment or label is posted to the PR.Evidence
sandbox.agent: false(no AWF chroot): Codex runs as root on the host → reads MCP config → callsadd_comment→ works correctlyec2-user(UID 1000) inside chroot → can't read root-owned MCP config → MCP tools invisible → no tool calls → no outputRoot Cause
The AWF chroot drops privileges to a non-root host user (e.g.
ec2-user, UID 1000) before executing Codex. However, the following files are created by root during compiler-generated setup steps and are not readable by the chroot user:/tmp/gh-aw/mcp-config/config.toml(GH_AW_MCP_CONFIG) — Codex reads this to discover MCP servers. When unreadable, Codex has no knowledge ofadd_comment/add_labels/nooptools and falls back to built-in tools only (exec_command, file reads, etc.)./opt/gh-aw/safeoutputs/outputs.jsonl(GH_AW_SAFE_OUTPUTS) — Even if Codex could call tools, the output file path is under root-owned/opt/gh-aw/.These files are created after any user-defined
steps:run (e.g.Write Safe Outputs Config,Start Safe Outputs MCP HTTP Server), so workflow-levelchmodworkarounds cannot fix them.The MCP gateway
tools/listresponses seen in gateway logs come from the gateway's own startup (running as root on the host), not from Codex inside the chroot. Codex inside the chroot never connects to the MCP gateway because it cannot read the config file.Why This Only Affects Self-Hosted Runners
On GitHub-hosted runners, the runner user has broader filesystem permissions. On self-hosted runners configured to run as root (common pattern for AWS EC2 runners), the AWF chroot drops to a non-root user that cannot read root-owned files under
/tmp/gh-aw/and/opt/gh-aw/.Observed Symptoms
Workflow job exits with code 0 (success) but the conclusion job logs:
Agentic Implementation Plan
File to modify:
containers/agent/entrypoint.shBefore the
capsh --user=${HOST_USER}privilege drop, add achmodto make gh-aw files accessible to the chroot user. Insert after the DNS configuration section (~line 430) and before thechroot /host /bin/bash -c "..."block:This mirrors how the entrypoint already handles
awfuserhome directory ownership:Tests to add in
src/docker-manager.test.tsor a new integration test:Environment
@openai/codexv0.115.0)--openai-api-target)root, AWF chroot drops toec2-user(UID 1000)Related
--openai-api-target/--anthropic-api-targetflags (merged)