ward pkg brew fails (sandbox make-rprivate: permission denied) in restricted namespaces, even for --help #108

Closed
opened 2026-06-17 09:45:05 +00:00 by coilysiren · 1 comment
Owner

Summary

ward pkg brew is unusable in restricted/nested mount namespaces — it fails before doing anything, including --help:

$ ward pkg brew --help
ward: sandbox: make-rprivate: permission denied
exit status 1

ward v0.21.0, linux/ser8, inside a Claude Code agent shell (a restricted namespace with no privilege to create a private mount namespace).

Impact

The sandbox is set up unconditionally before argv parsing, so every ward pkg brew invocation dies regardless of subcommand. In environments where the agent shell lacks CLONE_NEWNS / mount --make-rprivate privilege, the ward-native brew wrapper cannot run at all. The only working audited brew path there is coily pkg brew (no namespace sandbox). With coily being de-emphasized in favor of ward, that fallback is shrinking.

Concretely: this blocked migrating coily onto the central tap (coilyco-bridge/tap/coily) during the per-repo->central tap migration. coily self-removes when it uninstalls itself, ward pkg brew can't reinstall (sandbox), and bare brew is denied by lockdown — leaving no agent path to complete the swap.

Expected

Either degrade gracefully when the namespace op is denied (warn + run unsandboxed, or honor a WARD_NO_SANDBOX=1 / --no-sandbox escape), or skip sandbox setup for read-only verbs and --help. At minimum --help should not require the sandbox.

Filed from claude-linux-ser8 during the central-tap migration (infra 09197e8).

## Summary `ward pkg brew` is unusable in restricted/nested mount namespaces — it fails before doing anything, including `--help`: ``` $ ward pkg brew --help ward: sandbox: make-rprivate: permission denied exit status 1 ``` ward v0.21.0, linux/ser8, inside a Claude Code agent shell (a restricted namespace with no privilege to create a private mount namespace). ## Impact The sandbox is set up unconditionally before argv parsing, so every `ward pkg brew` invocation dies regardless of subcommand. In environments where the agent shell lacks `CLONE_NEWNS` / `mount --make-rprivate` privilege, the ward-native brew wrapper cannot run at all. The only working audited brew path there is `coily pkg brew` (no namespace sandbox). With coily being de-emphasized in favor of ward, that fallback is shrinking. Concretely: this blocked migrating coily onto the central tap (`coilyco-bridge/tap/coily`) during the per-repo->central tap migration. coily self-removes when it uninstalls itself, ward pkg brew can't reinstall (sandbox), and bare brew is denied by lockdown — leaving no agent path to complete the swap. ## Expected Either degrade gracefully when the namespace op is denied (warn + run unsandboxed, or honor a `WARD_NO_SANDBOX=1` / `--no-sandbox` escape), or skip sandbox setup for read-only verbs and `--help`. At minimum `--help` should not require the sandbox. Filed from claude-linux-ser8 during the central-tap migration (infra 09197e8).
Author
Owner

Reproduced live from a new angle while landing ward agent (ward#123/#125). Inside the dev container (ward agent codex work ... --detach, image agentic-os:latest, linux/arm64), the in-container reaper's ward container reap fails:

ward container reap: residual commit failed: fork/exec /usr/local/bin/ward: operation not permitted
ward container reap: salvage branch push failed (fork/exec /usr/local/bin/ward: operation not permitted); ...
ward: ward container reap: could not preserve work to the remote: fork/exec /usr/local/bin/ward: operation not permitted

ward version runs fine in the same container, but any verb that re-execs ward (the reaper shelling out) trips the sandbox Wrap (cli-guard cli/sandbox/sandbox_linux.go: CLONE_NEWUSER|CLONE_NEWNS + make-rprivate), which EPERMs in the container's restricted namespace - same root cause as the ward pkg brew report.

Impact specific to ward agent/ward container: the reaper backstop can't salvage residual work inside the container. Happy path is unaffected (the agent self-commits/pushes via bare git per AGENTS.container.md), so this only bites on crash/timeout with loose work. The container entrypoint could set a WARD_NO_SANDBOX-style escape once cli-guard's sandbox honors one (the graceful-degrade proposed here), which would also unblock the reaper.

Reproduced live from a new angle while landing `ward agent` (ward#123/#125). Inside the **dev container** (`ward agent codex work ... --detach`, image `agentic-os:latest`, linux/arm64), the in-container reaper's `ward container reap` fails: ``` ward container reap: residual commit failed: fork/exec /usr/local/bin/ward: operation not permitted ward container reap: salvage branch push failed (fork/exec /usr/local/bin/ward: operation not permitted); ... ward: ward container reap: could not preserve work to the remote: fork/exec /usr/local/bin/ward: operation not permitted ``` `ward version` runs fine in the same container, but any verb that re-execs ward (the reaper shelling out) trips the sandbox `Wrap` (cli-guard `cli/sandbox/sandbox_linux.go`: `CLONE_NEWUSER|CLONE_NEWNS` + make-rprivate), which EPERMs in the container's restricted namespace - same root cause as the `ward pkg brew` report. Impact specific to `ward agent`/`ward container`: the **reaper backstop can't salvage residual work** inside the container. Happy path is unaffected (the agent self-commits/pushes via bare git per AGENTS.container.md), so this only bites on crash/timeout with loose work. The container entrypoint could set a `WARD_NO_SANDBOX`-style escape once cli-guard's sandbox honors one (the graceful-degrade proposed here), which would also unblock the reaper.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
coilyco-flight-deck/ward#108
No description provided.