Container permission docs claim a single-repo blast radius, but --repo grants extra writable repos #473

Closed
opened 2026-07-01 22:39:19 +00:00 by coilyco-ops · 5 comments
Member

Why

Persona: security-skeptic / angle security-posture. This reader is deciding whether ward's container boundary is a real safety argument or just agent-safety rhetoric.

Cold trail: SECURITY.md -> docs/container-permissions.md -> docs/agent-flags.md -> docs/container-multi-repo.md.

docs/container-permissions.md justifies bypassPermissions by saying the container boundary is safe because the push token is scoped to the one target repo, no other repos are cloned or reachable, and the blast radius is the single target repo's history.

But the documented launch surface includes repeatable --repo, and docs/container-multi-repo.md says each grant is an additional writable repo, cloned as a full feature working copy with a real Forgejo push remote. It also says the preflight is told those grants are writable.

Those two docs cannot both be the general safety story. The single-repo blast-radius proof is true only for default runs, not for --repo runs. A security reviewer reading the permission posture will take away a stronger guarantee than the product actually provides.

Deliverable

Update the container permission/threat-model docs so the safety argument is parameterized by launch scope:

  • default run: one target repo, no extra writable repos;
  • --repo run: explicit named extra repos become writable blast radius;
  • what remains enforced vs doctrine-only when multiple repos are writable;
  • how the push token/scopes behave for target vs extra repos;
  • where the reaper does and does not land work (container-multi-repo.md says it lands only the target).

Link container-multi-repo.md from the permission posture section wherever the single-repo claim is made.

Done condition

A reader can no longer quote docs/container-permissions.md as proving that every warded run is limited to one repo. The doc clearly distinguishes the default one-repo boundary from the widened --repo boundary and states the resulting blast radius.


Severity: adoption-fatal · persona: security-skeptic · angle: security-posture
Filed by Codex during a cold-read release pressure test (run 32).

## Why Persona: `security-skeptic` / angle `security-posture`. This reader is deciding whether ward's container boundary is a real safety argument or just agent-safety rhetoric. Cold trail: SECURITY.md -> `docs/container-permissions.md` -> `docs/agent-flags.md` -> `docs/container-multi-repo.md`. `docs/container-permissions.md` justifies `bypassPermissions` by saying the container boundary is safe because the push token is scoped to the **one** target repo, no other repos are cloned or reachable, and the blast radius is the single target repo's history. But the documented launch surface includes repeatable `--repo`, and `docs/container-multi-repo.md` says each grant is an additional writable repo, cloned as a full feature working copy with a real Forgejo push remote. It also says the preflight is told those grants are writable. Those two docs cannot both be the general safety story. The single-repo blast-radius proof is true only for default runs, not for `--repo` runs. A security reviewer reading the permission posture will take away a stronger guarantee than the product actually provides. ## Deliverable Update the container permission/threat-model docs so the safety argument is parameterized by launch scope: - default run: one target repo, no extra writable repos; - `--repo` run: explicit named extra repos become writable blast radius; - what remains enforced vs doctrine-only when multiple repos are writable; - how the push token/scopes behave for target vs extra repos; - where the reaper does and does not land work (`container-multi-repo.md` says it lands only the target). Link `container-multi-repo.md` from the permission posture section wherever the single-repo claim is made. ## Done condition A reader can no longer quote `docs/container-permissions.md` as proving that every warded run is limited to one repo. The doc clearly distinguishes the default one-repo boundary from the widened `--repo` boundary and states the resulting blast radius. --- **Severity: adoption-fatal** · persona: security-skeptic · angle: security-posture Filed by Codex during a cold-read release pressure test (run 32).
coilyco-ops added this to the ward launch milestone 2026-07-01 23:29:27 +00:00
Author
Member

🔒 Reserved by ward agent --driver claude — container engineer-claude-ward-473 on host kais-macbook-pro-2.local is carrying this issue (reserved 2026-07-02T02:50:47Z). 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-473` on host `kais-macbook-pro-2.local` is carrying this issue (reserved 2026-07-02T02:50:47Z). 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`
Owner

WARD-OUTCOME: done - rewrote container-permissions.md to parameterize the blast radius by launch scope (default one repo vs --repo grants) and corrected the token claim; pushed to main as 10c6c51.

Reading the actual wiring changed the shape of this one. The issue framed it as "the docs are true for default runs but not --repo runs," which is right, but entrypoint.sh told a sharper story: the FORGEJO_TOKEN is the coilyco-ops bot's full host-wide credential, so the old "push token scoped to the one target repo" bullet was never accurate, even on a default run. The real boundary is which repos get cloned plus the doctrine wall, not the credential. So I reframed the whole posture around that rather than just bolting on a --repo caveat.

The thing that fought back was the catalog size caps (80 lines / 4000 chars). The honest version of this argument wants room, and I blew past both caps on the first draft, then spent a few rounds tightening prose to land at 79 lines / ~3983 chars. It reads fine, but it's dense - a follow-up worth considering is splitting a dedicated docs/container-threat-model.md so the posture has breathing room instead of being cap-golfed.

Confident in the accuracy: the token behavior is grounded in setup_git_auth, and the reaper/grant claims match container-reap.md and container-multi-repo.md. ward#318 (dispatch-only token) is the real fix that would turn this doctrine boundary into a credential one - the docs now point at it honestly instead of overclaiming.

WARD-OUTCOME: done - rewrote container-permissions.md to parameterize the blast radius by launch scope (default one repo vs `--repo` grants) and corrected the token claim; pushed to main as 10c6c51. Reading the actual wiring changed the shape of this one. The issue framed it as "the docs are true for default runs but not `--repo` runs," which is right, but `entrypoint.sh` told a sharper story: the `FORGEJO_TOKEN` is the coilyco-ops bot's full host-wide credential, so the old "push token scoped to the one target repo" bullet was never accurate, even on a default run. The real boundary is which repos get cloned plus the doctrine wall, not the credential. So I reframed the whole posture around that rather than just bolting on a `--repo` caveat. The thing that fought back was the catalog size caps (80 lines / 4000 chars). The honest version of this argument wants room, and I blew past both caps on the first draft, then spent a few rounds tightening prose to land at 79 lines / ~3983 chars. It reads fine, but it's dense - a follow-up worth considering is splitting a dedicated `docs/container-threat-model.md` so the posture has breathing room instead of being cap-golfed. Confident in the accuracy: the token behavior is grounded in `setup_git_auth`, and the reaper/grant claims match container-reap.md and container-multi-repo.md. ward#318 (dispatch-only token) is the real fix that would turn this doctrine boundary into a credential one - the docs now point at it honestly instead of overclaiming.
Author
Member

🔒 Reserved by ward agent --driver claude — container engineer-claude-ward-473 on host kais-macbook-pro-2.local is carrying this issue (reserved 2026-07-02T08:11:04Z). 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-473` on host `kais-macbook-pro-2.local` is carrying this issue (reserved 2026-07-02T08:11:04Z). 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
Member

🔒 Reserved by ward agent --driver claude — container engineer-claude-ward-473 on host kais-macbook-pro-2.local is carrying this issue (reserved 2026-07-02T08:11:04Z). 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-473` on host `kais-macbook-pro-2.local` is carrying this issue (reserved 2026-07-02T08:11:04Z). 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`
Owner

WARD-OUTCOME: done - already landed by a prior run; container-permissions.md parameterizes the blast radius by launch scope (default one repo vs --repo grants) and 10c6c51 (closes #473) is on origin/main.

Re-dispatch retrospective (this run): I opened the clone expecting to write this doc and found it already done. Commit 10c6c51 from the earlier engineer-claude-ward-473 container had already rewritten docs/container-permissions.md exactly as the deliverable asks - default = one target repo, --repo = named grants become writable blast radius, a "push token is not the boundary" section calling out the host-wide coilyco-ops credential, the reaper-lands-only-the-target note, and both-ways links to container-multi-repo.md. It is on origin/main, the issue is closed, the tree is clean and synced, and both docs sit right under the catalog caps (79 lines / ~3983 chars).

So there was genuinely nothing to build. The one judgement call was to NOT manufacture a no-op commit or reopen a closed issue just to have something to push - that would be noise, not finishing. I verified the done condition against the actual file rather than trusting the closed state, and it holds: a reader can no longer quote this doc as proving every warded run is one repo.

Confidence: high that #473 is satisfied. The only open thread is the same one the prior run flagged - ward#318 (a repo-scoped/dispatch-only token) is what would turn this doctrine boundary into a real credential boundary, and the doc already points there honestly. No new follow-up needed from this pass.

WARD-OUTCOME: done - already landed by a prior run; container-permissions.md parameterizes the blast radius by launch scope (default one repo vs `--repo` grants) and 10c6c51 (closes #473) is on origin/main. Re-dispatch retrospective (this run): I opened the clone expecting to write this doc and found it already done. Commit 10c6c51 from the earlier `engineer-claude-ward-473` container had already rewritten `docs/container-permissions.md` exactly as the deliverable asks - default = one target repo, `--repo` = named grants become writable blast radius, a "push token is not the boundary" section calling out the host-wide coilyco-ops credential, the reaper-lands-only-the-target note, and both-ways links to `container-multi-repo.md`. It is on origin/main, the issue is closed, the tree is clean and synced, and both docs sit right under the catalog caps (79 lines / ~3983 chars). So there was genuinely nothing to build. The one judgement call was to NOT manufacture a no-op commit or reopen a closed issue just to have something to push - that would be noise, not finishing. I verified the done condition against the actual file rather than trusting the closed state, and it holds: a reader can no longer quote this doc as proving every warded run is one repo. Confidence: high that #473 is satisfied. The only open thread is the same one the prior run flagged - ward#318 (a repo-scoped/dispatch-only token) is what would turn this doctrine boundary into a real credential boundary, and the doc already points there honestly. No new follow-up needed from this pass.
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#473
No description provided.