harden(explore): broker read op so Unit D can scrub FORGEJO_TOKEN (finishes the ward#329 boundary) #608

Closed
opened 2026-07-04 17:35:00 +00:00 by coilysiren · 0 comments
Owner

The remaining broker unit (was Unit D of ward#329)

ward#329 (Unit B, the root credential broker daemon + entrypoint lifecycle +
ward-kdl-write ship) and ward#334 (Unit C, routing the write/dispatch clients
through the socket) both landed. What is not done is Unit D - dropping the
raw FORGEJO_TOKEN from the dropped agent's env
. The broker holds the token
today, but the agent still holds it too (documented "Dual mode (not a cutover)"
in docs/broker.md). Until the raw token is gone, the ward#329 boundary
("credential-enforced by absence") is only half-real.

Why Unit D can't just scrub the token

A naive scrub at the setpriv drop breaks every forge read in an explore /
read-only session. Concretely:

  • Forge reads (get / list / list-all / search / view) go direct
    in a brokered box - broker_client.go's forgejoReadVerbs sends them straight
    to ward ops forgejo, which resolves auth from env FORGEJO_TOKEN (the
    agent-held token). Scrub the token and these fail with no creds.
  • ward-kdl-read can't fill the gap: its guardfile authenticates from SSM
    (ssm /forgejo/coilyco-ops/api-token), and an explore container has no AWS /
    SSM
    . Only the write tier was given the value env "FORGEJO_TOKEN" auth
    override; read stays SSM.
  • The broker can't serve reads either: cli-guard/pkg/broker's protocol has only
    OpFileIssue / OpEditIssue / OpCommentIssue / OpDispatch - no read op.

The actual fix (cli-guard first, then ward)

  1. cli-guard - add a read op to pkg/broker (protocol + authorizer + executor
    interface), so a brokered read round-trips like a write. This is the piece that
    lives upstream and blocks the ward side. Fits the ward#267 / ward#268 broker
    convergence (dispatch + credseed extraction) and cli-guard#139.
  2. ward - the executor shells ward-kdl-write ops forgejo issue get ... (the
    write tier already includes read, env-token auth), the client routes
    forgejoReadVerbs through the broker instead of direct, and only then can
    the entrypoint scrub FORGEJO_TOKEN from the dropped agent's env at the drop
    (the way ANTHROPIC_* already is), gated on WARD_READONLY.

Do these in that order: the scrub is the last step and must not land before
reads route through the broker, or explore sessions go blind.

ward#329 (Unit B, landed), ward#334 (Unit C, landed), ward#267 + ward#268
(cli-guard dispatch + credseed convergence), cli-guard#139. See docs/broker.md
"Dual mode (not a cutover)".

## The remaining broker unit (was Unit D of ward#329) ward#329 (Unit B, the root credential broker daemon + entrypoint lifecycle + `ward-kdl-write` ship) and ward#334 (Unit C, routing the write/dispatch clients through the socket) both landed. What is **not** done is **Unit D - dropping the raw `FORGEJO_TOKEN` from the dropped agent's env**. The broker holds the token today, but the agent still holds it too (documented "Dual mode (not a cutover)" in docs/broker.md). Until the raw token is gone, the ward#329 boundary ("credential-enforced by absence") is only half-real. ## Why Unit D can't just scrub the token A naive scrub at the `setpriv` drop **breaks every forge read** in an explore / read-only session. Concretely: * Forge **reads** (`get` / `list` / `list-all` / `search` / `view`) go **direct** in a brokered box - `broker_client.go`'s `forgejoReadVerbs` sends them straight to `ward ops forgejo`, which resolves auth from env `FORGEJO_TOKEN` (the agent-held token). Scrub the token and these fail with no creds. * `ward-kdl-read` can't fill the gap: its guardfile authenticates from **SSM** (`ssm /forgejo/coilyco-ops/api-token`), and an explore container has **no AWS / SSM**. Only the **write** tier was given the `value env "FORGEJO_TOKEN"` auth override; read stays SSM. * The broker can't serve reads either: `cli-guard/pkg/broker`'s protocol has only `OpFileIssue` / `OpEditIssue` / `OpCommentIssue` / `OpDispatch` - **no read op**. ## The actual fix (cli-guard first, then ward) 1. **cli-guard** - add a read op to `pkg/broker` (protocol + authorizer + executor interface), so a brokered read round-trips like a write. This is the piece that lives upstream and blocks the ward side. Fits the ward#267 / ward#268 broker convergence (dispatch + credseed extraction) and cli-guard#139. 2. **ward** - the executor shells `ward-kdl-write ops forgejo issue get ...` (the write tier already includes read, env-token auth), the client routes `forgejoReadVerbs` through the broker instead of direct, and only **then** can the entrypoint scrub `FORGEJO_TOKEN` from the dropped agent's env at the drop (the way `ANTHROPIC_*` already is), gated on `WARD_READONLY`. Do these in that order: the scrub is the **last** step and must not land before reads route through the broker, or explore sessions go blind. ## Related ward#329 (Unit B, landed), ward#334 (Unit C, landed), ward#267 + ward#268 (cli-guard dispatch + credseed convergence), cli-guard#139. See docs/broker.md "Dual mode (not a cutover)".
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#608
No description provided.