T98: setup-route credential handling - #17
Conversation
The setup route becomes two steps: a GET that renders a prompt, and a POST that carries the value in a request body. `setupIsOpen()` names the configuration question that `registrationForm(...)` returning null was standing in for, so asking it no longer mints and signs a state as a side effect. Invariants, stated where the route is: * the value never appears in a request line, so nothing that records one keeps a copy of it; * the registration form is served only to a request that presented the value; every other request gets the same answer it got before; * with no setup token configured there is no route here at all, so a deployment that has finished registering gives nothing away. One previously pinned behaviour changes: a bare GET renders a prompt rather than answering 404. The trade is written down next to the test that used to pin it, and four new tests assert what that 404 was protecting. See T98. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01D5xdKhPXJT4HMWwUyENiu1
|
Follow-up review found two stale operator paths after the change to how the Fixed at Trade-off: the test boots a second server with registration values removed so Detail is tracked privately under T98. |
|
Dependency follow-up at |
|
this might be better served by this kit, is this a shape that will be reused by many apps, or is it specific to github? |
|
Exact-head review at Two earlier corrections were confirmed, along with passing hosted checks. One setup-lifecycle boundary still needed implementation work. The reproduction, impact analysis, and line-level reasoning are maintained in the private assurance record rather than repeated on this public pull request. Follow-up remediation and verification are recorded below. |
A configured setup token must not reopen registration after the app has credentials. Keep setup reachable only while registration is incomplete.
|
T98 follow-up remediation is pushed at The setup lifecycle now closes when registration is complete. A real-server regression test covered both request methods before and after the implementation change. Verification on the committed tree: 294/294 tests, typecheck, production build, dependency audit, and whitespace checks all pass. Trade-off: reopening setup now requires first removing the existing four-part registration configuration; restoring the setup value alone is deliberately insufficient. Local verification used Node 22.15 while the repository declares Node 24, so hosted Node 24 remains the runtime-version evidence. Detailed reasoning is tracked privately under T98. |
|
Following up on whether this belongs in The kit already owns the reusable primitives—constant-time setup-token comparison and signed state. This PR's remaining behavior is provider-specific: GitHub organization selection, manifest construction, the four GitHub registration credentials, registration-completion closure, route responses, and operator copy. Moving that shape into the kit now would couple the generic package to GitHub without a second implementation demonstrating a stable abstraction. I also fixed the test-environment cleanup issue in |
Tracked as T98. Details remain in the private security tracker; this public description records the contract and verification without reproducing sensitive review material.
Outcome
undefined(which Node can coerce to the string"undefined").The route intentionally serves a credential prompt while setup is pending. That briefly reveals that setup is open, but avoids putting a durable credential in access logs, browser history, and referrers.
TDD and verification
tsc --noEmitpassed.Boundary and tradeoff
initiative-app-kitcontinues to own generic setup-token comparison and state signing. The organization prompt, GitHub manifest, registration-completion condition, route behavior, and copy remain here because they are GitHub-specific. Extracting them would couple the generic kit to one provider's lifecycle without a second consumer.