As shipped, ward can only target forgejo.coilysiren.me: endpoint, SSM token path, and a coily* owner gate are compiled in, and no doc says so before install #441

Closed
opened 2026-07-01 21:54:51 +00:00 by coilyco-ops · 6 comments
Member

Why

Persona: forgejo-selfhoster (the ICP), walking zero → warded #<issue> on their own instance; angle install-path. The install mechanics are clean — the tap formula is current (v0.242.0, bump automation working) and builds from source. The wall is immediately after install: no README or docs section says how ward learns which Forgejo to talk to. Chasing that question through public config surfaces:

  • cmd/ward-kdl/ward-kdl.forgejo.guardfile.kdl: base-url "forgejo.coilysiren.me/api/v1" — compiled into the ops surface (ward-kdl.md: "a withheld verb is absent at compile time").
  • Same file: auth header-token { … value ssm "/forgejo/coilyco-ops/api-token" } — the API token resolves from coilyco's private AWS SSM parameter, unreadable outside the org.
  • Same file: restrict owner matches coily* — every owner-scoped verb structurally refuses repos not owned by coily*.
  • cmd/ward-kdl/ward-kdl.fleet.kdl: attribution defaults name=coilyco-ops email=coilyco-ops@coilysiren.me, embedded via fleetassets/.
  • docs/fleet-local.md: the only operator-local override (~/.ward/fleet.local.kdl) "carries only the narrow per-host node set (today the director block); the embed-only fleet block is rejected" — the endpoint cannot be repointed after install.
  • docs/agent-credentials.md: containers push with "the bot FORGEJO_TOKEN" — which bot, what scopes, and where the host reads it from are stated nowhere.

Net: a Forgejo self-hoster following the sanctioned brew path gets a binary that can only operate against the author's instance and orgs. Retargeting means fork + edit guardfile & fleet manifest + rebuild — a path no doc describes either. The repo description ("carries Forgejo issues end to end") and README carry no qualifier. This is the run-1 calibration miss one level deeper: not "requires Forgejo" but "requires this Forgejo" — invisible from inside the project, fatal from outside, and discovered only after install.

Deliverable

Two independently shippable halves; this issue is satisfied by (1) alone:

  1. Honesty fix, docs-only: README (before the install section) + repo description state plainly that ward as shipped targets forgejo.coilysiren.me / coily* orgs, and that running against your own instance currently requires a source build with an edited fleet manifest + forgejo guardfile (link both files). One paragraph.
  2. The actual retargeting path (endpoint / token source / owner gate as operator config) is ward#395 + ward#396 territory — link, don't duplicate.

Done condition

A Forgejo self-hoster reading the front page can answer "can I use this with my instance today?" correctly — today the honest answer is "not without a modified source build" — before running brew install. Anchors: #395 (externalize infra topology: hosts, SSM, registry), #396 (externalize fleet org/repo inventory).


Severity: adoption-fatal · persona: forgejo-selfhoster · angle: install-path
Filed by Claude Code during a cold-read release pressure test (run 12).

## Why Persona: `forgejo-selfhoster` (the ICP), walking zero → `warded #<issue>` on **their own instance**; angle `install-path`. The install mechanics are clean — the tap formula is current (v0.242.0, bump automation working) and builds from source. The wall is immediately after install: no README or docs section says how ward learns *which Forgejo to talk to*. Chasing that question through public config surfaces: - `cmd/ward-kdl/ward-kdl.forgejo.guardfile.kdl`: `base-url "forgejo.coilysiren.me/api/v1"` — compiled into the ops surface (ward-kdl.md: "a withheld verb is absent at compile time"). - Same file: `auth header-token { … value ssm "/forgejo/coilyco-ops/api-token" }` — the API token resolves from coilyco's private AWS SSM parameter, unreadable outside the org. - Same file: `restrict owner matches coily*` — every owner-scoped verb structurally refuses repos not owned by `coily*`. - `cmd/ward-kdl/ward-kdl.fleet.kdl`: attribution defaults `name=coilyco-ops email=coilyco-ops@coilysiren.me`, embedded via `fleetassets/`. - `docs/fleet-local.md`: the only operator-local override (`~/.ward/fleet.local.kdl`) "carries only the narrow per-host node set (today the `director` block); the embed-only `fleet` block is **rejected**" — the endpoint cannot be repointed after install. - `docs/agent-credentials.md`: containers push with "the bot `FORGEJO_TOKEN`" — which bot, what scopes, and where the host reads it from are stated nowhere. Net: a Forgejo self-hoster following the sanctioned brew path gets a binary that can only operate against the author's instance and orgs. Retargeting means fork + edit guardfile & fleet manifest + rebuild — a path no doc describes either. The repo description ("carries Forgejo issues end to end") and README carry no qualifier. This is the run-1 calibration miss one level deeper: not "requires Forgejo" but "requires *this* Forgejo" — invisible from inside the project, fatal from outside, and discovered only *after* install. ## Deliverable Two independently shippable halves; this issue is satisfied by (1) alone: 1. **Honesty fix, docs-only:** README (before the install section) + repo description state plainly that ward as shipped targets `forgejo.coilysiren.me` / `coily*` orgs, and that running against your own instance currently requires a source build with an edited fleet manifest + forgejo guardfile (link both files). One paragraph. 2. The actual retargeting path (endpoint / token source / owner gate as operator config) is ward#395 + ward#396 territory — link, don't duplicate. ## Done condition A Forgejo self-hoster reading the front page can answer "can I use this with my instance today?" correctly — today the honest answer is "not without a modified source build" — *before* running `brew install`. Anchors: #395 (externalize infra topology: hosts, SSM, registry), #396 (externalize fleet org/repo inventory). --- **Severity: adoption-fatal** · persona: forgejo-selfhoster · angle: install-path Filed by Claude Code during a cold-read release pressure test (run 12).
Author
Member

Direction update (Kai, 2026-07-01): three planned changes restructure this finding's story — #453 (KDL specs move up into aos as a swappable build input), #454 (full binary matrix to GitHub with checksums), #455 (ward-kdl leaves the public artifacts). Together they separate the generic product from the coilyco deployment.

Two things they do not change:

  1. None of the three gives a self-hoster runtime retargeting — that remains #395/#396 territory.
  2. The honesty-fix half of THIS issue (one README paragraph stating the current coupling, before the install section) should ship first and not be gated on the re-architecture. It is a five-minute change that converts the sweep's worst finding from 'misled' to 'informed'.

Filed by Claude Code, capturing Kai's release-direction decisions from the 2026-07-01 pressure-test debrief.

Direction update (Kai, 2026-07-01): three planned changes restructure this finding's story — #453 (KDL specs move up into aos as a swappable build input), #454 (full binary matrix to GitHub with checksums), #455 (ward-kdl leaves the public artifacts). Together they separate the generic product from the coilyco deployment. Two things they do not change: 1. None of the three gives a self-hoster runtime retargeting — that remains #395/#396 territory. 2. The honesty-fix half of THIS issue (one README paragraph stating the current coupling, before the install section) should ship first and not be gated on the re-architecture. It is a five-minute change that converts the sweep's worst finding from 'misled' to 'informed'. Filed by Claude Code, capturing Kai's release-direction decisions from the 2026-07-01 pressure-test debrief.
Author
Member

+1 — independently hit via forgejo-selfhoster/front-page, run 14. README never uses self-hosting language ("your instance", "self-host") anywhere; combined with the hardcoded endpoint/org this issue already covers, the front page reads as written for the authors own setup, not a general self-hoster audience.

+1 — independently hit via forgejo-selfhoster/front-page, run 14. README never uses self-hosting language ("your instance", "self-host") anywhere; combined with the hardcoded endpoint/org this issue already covers, the front page reads as written for the authors own setup, not a general self-hoster audience.
Author
Member

+1 — independently hit via agent-power-user/feature-gaps, run 29.

+1 — independently hit via agent-power-user/feature-gaps, run 29.
Author
Member

+1, empirically confirmed in run 17 (first-run angle, actual installed binary v0.242.0): warded engineer someorg/somerepo#1 --print refuses with refusing untrusted owner "someorg" (allowed: coilysiren, coilyco-bridge, coilyco-flight-deck, coilyco-gaming) - the compiled-in allowlist this issue describes from static KDL analysis is live and enforced in the shipped binary, not just a source-level finding.

+1, empirically confirmed in run 17 (first-run angle, actual installed binary v0.242.0): `warded engineer someorg/somerepo#1 --print` refuses with `refusing untrusted owner "someorg" (allowed: coilysiren, coilyco-bridge, coilyco-flight-deck, coilyco-gaming)` - the compiled-in allowlist this issue describes from static KDL analysis is live and enforced in the shipped binary, not just a source-level finding.
coilyco-ops added this to the ward launch milestone 2026-07-01 23:29:39 +00:00
Author
Member

🔒 Reserved by ward agent --driver claude — container engineer-claude-ward-441 on host kais-macbook-pro-2.local is carrying this issue (reserved 2026-07-02T07:10:16Z). 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-441` on host `kais-macbook-pro-2.local` is carrying this issue (reserved 2026-07-02T07:10:16Z). 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 - README now states plainly (before Install) that ward ships targeting forgejo.coilysiren.me / coily* orgs and retargeting needs a source build; repo description updated to match.

The deliverable itself was small - one honest paragraph - but the README was sitting right at the documentation-layout size caps (130 lines / 13300 chars), so the real work was making room. Adding ~1KB of truth meant clawing back an equal amount from surrounding prose, which turned into a few rounds of tightening verbose sentences and folding a redundant paragraph until both caps went green. That fight was more interesting than the fix.

I placed the note under 'What it requires' as a bolded lead rather than a new '## Which Forgejo?' header, purely to save the two lines a header costs - the Forgejo-requirement bullet now points down to it. Confidence is high: it is docs-only, all hooks pass, the note links the exact two files a retargeting build must edit and defers the actual mechanism to #395/#396 as the issue asked. No follow-ups beyond those already-open anchors. One soft rough edge for future doc work: this README is chronically at its size ceiling, so the next substantive addition will hit the same wall - splitting some 'What it does' detail into docs/*.md would give it breathing room.

WARD-OUTCOME: done - README now states plainly (before Install) that ward ships targeting forgejo.coilysiren.me / coily* orgs and retargeting needs a source build; repo description updated to match. The deliverable itself was small - one honest paragraph - but the README was sitting right at the documentation-layout size caps (130 lines / 13300 chars), so the real work was making room. Adding ~1KB of truth meant clawing back an equal amount from surrounding prose, which turned into a few rounds of tightening verbose sentences and folding a redundant paragraph until both caps went green. That fight was more interesting than the fix. I placed the note under 'What it requires' as a bolded lead rather than a new '## Which Forgejo?' header, purely to save the two lines a header costs - the Forgejo-requirement bullet now points down to it. Confidence is high: it is docs-only, all hooks pass, the note links the exact two files a retargeting build must edit and defers the actual mechanism to #395/#396 as the issue asked. No follow-ups beyond those already-open anchors. One soft rough edge for future doc work: this README is chronically at its size ceiling, so the next substantive addition will hit the same wall - splitting some 'What it does' detail into docs/*.md would give it breathing room.
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#441
No description provided.