allow ward docker exec into warded containers #220

Closed
opened 2026-06-19 07:38:11 +00:00 by coilysiren · 6 comments
Owner
No description provided.
coilyco-ops added
P4
and removed
P3
labels 2026-06-24 17:20:02 +00:00
Member

Re-triage (goose-triage method, claude-macos-kais-macbook-pro-2 as the judgment engine, 2026-06-24)

  • P4 - allow ward docker exec, one-line feature wish, icebox.
  • consult - Needs a design decision on the security tradeoff first.
<!-- goose-triage --> **Re-triage** (goose-triage method, claude-macos-kais-macbook-pro-2 as the judgment engine, 2026-06-24) - **P4** - allow ward docker exec, one-line feature wish, icebox. - **consult** - Needs a design decision on the security tradeoff first.
Member

Re-triage (goose-triage method, claude-macos-kais-macbook-pro-2 as the judgment engine, 2026-06-24)

  • P4 - allow ward docker exec, one-line feature wish, icebox.
  • consult - Needs a design decision on the security tradeoff first.
<!-- goose-triage --> **Re-triage** (goose-triage method, claude-macos-kais-macbook-pro-2 as the judgment engine, 2026-06-24) - **P4** - allow ward docker exec, one-line feature wish, icebox. - **consult** - Needs a design decision on the security tradeoff first.
Member

Flipped headless: small feature (ward docker exec into warded containers); document what exec bypasses relative to the container-permissions posture in the same PR. Recorded by Claude Code (Fable) during the 2026-07-01 ward launch triage session with Kai.

Flipped headless: small feature (ward docker exec into warded containers); document what exec bypasses relative to the container-permissions posture in the same PR. Recorded by Claude Code (Fable) during the 2026-07-01 ward launch triage session with Kai.
Member

🔒 Reserved by ward agent --driver claude — container engineer-claude-ward-220 on host KAI-DESKTOP-TOWER is carrying this issue (reserved 2026-07-03T07:06:42Z). Concurrent ward agent runs are blocked until it finishes or the reservation goes stale (2h0m0s TTL); --force overrides.

— Claude (she/her), via ward agent

<!-- ward-agent-reservation --> 🔒 Reserved by `ward agent --driver claude` — container `engineer-claude-ward-220` on host `KAI-DESKTOP-TOWER` is carrying this issue (reserved 2026-07-03T07:06:42Z). Concurrent `ward agent` runs are blocked until it finishes or the reservation goes stale (2h0m0s TTL); `--force` overrides. <!-- ward-agent-signature --> — Claude (she/her), via `ward agent`
Member

🔒 Reserved by ward agent --driver claude — container engineer-claude-ward-220 on host KAI-DESKTOP-TOWER is carrying this issue (reserved 2026-07-03T07:18:43Z). Concurrent ward agent runs are blocked until it finishes or the reservation goes stale (2h0m0s TTL); --force overrides.

— Claude (she/her), via ward agent

<!-- ward-agent-reservation --> 🔒 Reserved by `ward agent --driver claude` — container `engineer-claude-ward-220` on host `KAI-DESKTOP-TOWER` is carrying this issue (reserved 2026-07-03T07:18:43Z). Concurrent `ward agent` runs are blocked until it finishes or the reservation goes stale (2h0m0s TTL); `--force` overrides. <!-- ward-agent-signature --> — Claude (she/her), via `ward agent`
Author
Owner

WARD-OUTCOME: done - ward docker exec ships as a hand-written, ward=true-gated leaf on the read-only docker surface, landed on main.

The shape of this one was decided the moment I read the existing docker guardfile: its own header comment already said exec was "gated separately in ward#220", so the design intent was sitting right there. The real judgment call was that exec cannot be a guardfile grant at all - whether a container is ward-managed is a runtime label lookup, not an argv shape - so it had to be a hand-written command grafted onto the guardfile-built group, mirroring the graftForgejoAdminExec pattern.

What fought back a little: parsing the CONTAINER positional out of a docker exec argv correctly. -it, -e K=V, -eK=V, --env=..., --, bundled shorts ending in a value flag - I ended up writing a small walker over docker exec's actual (bounded) flag table rather than guessing, and table-tested it hard, because getting it wrong means the gate checks the wrong token. The other snag was purely mechanical: FEATURES.md was sitting exactly on the 12500-char cap with zero headroom, so fitting a one-line mention meant trimming adjacent prose char-by-char. Folding the mention into the existing exec-dialect sentence was cleaner than a new bullet anyway.

Confidence is high on the gate logic and the parser (well covered by tests, and the real binary refuses a non-warded/missing container correctly). The one thing I could not exercise here is a live docker exec -it into a real warded container - no daemon in this box - so the interactive-TTY path is verified by construction (stdio is wired through the shared Runner, same as every other docker call) rather than by a live run. If a follow-up is wanted, a small integration test behind a docker-available build tag would close that last gap. The security posture and what exec deliberately bypasses is written up in docs/ward-docker-exec.md, per the issue's design-decision ask.

WARD-OUTCOME: done - `ward docker exec` ships as a hand-written, ward=true-gated leaf on the read-only docker surface, landed on main. The shape of this one was decided the moment I read the existing docker guardfile: its own header comment already said exec was "gated separately in ward#220", so the design intent was sitting right there. The real judgment call was that exec cannot be a guardfile grant at all - whether a container is ward-managed is a runtime label lookup, not an argv shape - so it had to be a hand-written command grafted onto the guardfile-built group, mirroring the graftForgejoAdminExec pattern. What fought back a little: parsing the CONTAINER positional out of a `docker exec` argv correctly. `-it`, `-e K=V`, `-eK=V`, `--env=...`, `--`, bundled shorts ending in a value flag - I ended up writing a small walker over docker exec's actual (bounded) flag table rather than guessing, and table-tested it hard, because getting it wrong means the gate checks the wrong token. The other snag was purely mechanical: FEATURES.md was sitting exactly on the 12500-char cap with zero headroom, so fitting a one-line mention meant trimming adjacent prose char-by-char. Folding the mention into the existing exec-dialect sentence was cleaner than a new bullet anyway. Confidence is high on the gate logic and the parser (well covered by tests, and the real binary refuses a non-warded/missing container correctly). The one thing I could not exercise here is a live `docker exec -it` into a real warded container - no daemon in this box - so the interactive-TTY path is verified by construction (stdio is wired through the shared Runner, same as every other docker call) rather than by a live run. If a follow-up is wanted, a small integration test behind a `docker`-available build tag would close that last gap. The security posture and what exec deliberately bypasses is written up in docs/ward-docker-exec.md, per the issue's design-decision ask.
Sign in to join this conversation.
No milestone
No project
No assignees
2 participants
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#220
No description provided.