docs(relay): Phase 0 runnable-relay build spec (PLAN_RELAY_RUN_PHASE0.md)
File-level plan for a single-host `npm start` relay: new relay-run/ package wiring the real P4/P5 + in-memory control-plane + self-signed TLS + agent + relay-web. Seam files to read, 9-step build order, verify steps. Executable spec for a fresh build session; reuses the e2e/harness wiring.
This commit is contained in:
52
docs/PLAN_RELAY_RUN_PHASE0.md
Normal file
52
docs/PLAN_RELAY_RUN_PHASE0.md
Normal file
@@ -0,0 +1,52 @@
|
||||
# Phase 0 — single-host runnable relay (build spec)
|
||||
|
||||
> Goal: a single `npm start` that boots an **end-to-end relay you can click through locally** —
|
||||
> real P4(crypto)+P5(auth) wiring, in-memory stores, self-signed TLS, agent dialing `localhost`,
|
||||
> `relay-web` served. No Postgres/Redis/KMS. This is the executable spec for the Phase 0 milestone
|
||||
> in [DEPLOY_RELAY.md](./DEPLOY_RELAY.md) §4. Reuses the wiring proven in `e2e/harness/`.
|
||||
>
|
||||
> **Run this build in a FRESH session** (recommend `/compact` first). Read the seam files named below
|
||||
> before writing — the exact interface shapes must be confirmed against the code, not assumed.
|
||||
|
||||
## Deliverable
|
||||
A new package `relay-run/` (top-level, symlink node_modules like `e2e/`) with one entry
|
||||
`relay-run/src/main.ts` that `npm start` runs, plus small wiring modules. Result: browser at
|
||||
`https://localhost:8443/` → authenticates → live terminal to a shell on the same machine, spliced
|
||||
through the real relay-node, E2E-encrypted (relay sees only ciphertext).
|
||||
|
||||
## Seam files to read FIRST (confirm exact shapes)
|
||||
- `term-relay/data-plane/ws-like.ts` — the `WebSocketLike` interface the relay-node consumes.
|
||||
- `term-relay/data-plane/agent-listener.ts` — `AgentListener`/`AgentTunnel` shapes (how an agent mux attaches).
|
||||
- `term-relay/data-plane/relay-node.ts` + `upgrade.ts` + `authz-port.ts` — `createRelayNode`, `authorizeUpgrade`, the `Authorizer` port (`onUpgrade`/`onReattach`).
|
||||
- `term-relay/mux/mux-session.ts` — `createMuxSession`, `MuxStreamHandle` (frame the agent side).
|
||||
- `control-plane/src/main.ts` — `buildControlPlane`/overrides (`stores`, `verifier`, `bus`, `kmsResolver`), `createMemoryStores`, `inProcessCaSigner`.
|
||||
- `agent/src/cli.ts` + `agent/src/e2e/hostEndpoint.ts` + `transport/dial.ts` — how the agent dials + runs the E2E host endpoint + loopback splice.
|
||||
- `e2e/harness/world.ts` — the REFERENCE wiring: it already composes real P5 `onUpgrade` + P4 handshake + fakes. Lift the `EnforceDeps`/registry/bucket/audit construction from here (and `e2e/harness/fakes.ts`).
|
||||
|
||||
## Build steps (order)
|
||||
1. **Scaffold `relay-run/`**: `package.json` (type module, `"start":"tsx src/main.ts"`, dep on `tsx`, `ws`), `tsconfig.json`, and `node_modules` symlinks to all relay packages + `ws`/`tsx` (mirror `e2e/`’s manual-symlink approach — avoids `npm install`). Add `relay-run/node_modules` to `.gitignore` coverage (root already ignores `node_modules/`).
|
||||
2. **Self-signed TLS**: generate a localhost cert at boot (node `selfsigned` or a checked-in dev cert) for the browser WSS listener; a throwaway CA for agent mTLS.
|
||||
3. **Control-plane (in-memory)**: boot `buildControlPlane` with `overrides = { stores: createMemoryStores(), verifier: <real P5 verifyCapabilityToken bound to the dev P5 pubkey>, bus: in-memory, kmsResolver: inProcessCaSigner }`. Listen on `:8080`. Seed one account + issue a pairing code programmatically at boot.
|
||||
4. **P5 EnforceDeps**: build the real `EnforceDeps` (hosts/sessions/revocation/buckets/audit + `stepUpPolicyFor: () => NO_STEPUP_POLICY`) backed by the in-memory control-plane registries — copy the construction from `e2e/harness`. Configure the P5 verify key (`configureVerifyKey`).
|
||||
5. **`WebSocketLike` adapter**: wrap `ws` `WebSocket` → the `WebSocketLike` interface (send/close/onmessage/onclose per ws-like.ts). Browser WSS server on `:8443`; on upgrade, build the `UpgradeRequest` (extract token from subprotocol/cookie, Origin, DPoP header) and call `authorizeUpgrade` (→ real `onUpgrade`). **Close F2 here**: pass a resolved principal when the host policy requires step-up (Phase 0 default policy = not-required, so `null` is fine).
|
||||
6. **`AgentListener` adapter**: mTLS `tls.Server` on `:8444`; verify the agent client cert against the dev CA (`verifyAgentCert`), attach each as an `AgentTunnel` + `createMuxSession`. Wire `createRelayNode({ config, agentListener, authorizer })` and the opaque splice.
|
||||
7. **Agent**: build the CLI (`dist/cli.js`) or run `agent` in-process; enroll against control-plane `POST /enroll` with the seeded pairing code (→ SPIFFE cert + `hostContentSecret` + subdomain); dial `wss://localhost:8444` (mTLS) and run the E2E host endpoint splicing to a local shell (`LOCAL_TARGET_URL` / node-pty).
|
||||
8. **relay-web**: `npm --prefix relay-web run build`; serve the bundle from the browser listener (same origin as WSS so Origin/CSWSH passes). Wire the login → P5 capability-token mint (Phase 0: a dev endpoint that mints a token after a stub human-auth, or reuse `issueCapabilityToken` directly).
|
||||
9. **`main.ts`**: bring up 3→5→6→7→8 in order; print the URL + a ready-to-use token/subdomain.
|
||||
|
||||
## Verify
|
||||
- `npm start` in `relay-run/` boots without error; console prints the local URL + subdomain.
|
||||
- Browser: open `https://localhost:8443/?...`, authenticate, see a live shell; type `whoami` → output.
|
||||
- Kill/restart the agent → session survives per design (reconnect); `revoke()` → stream tears down.
|
||||
- Add a smoke test (Vitest) that boots the world in-process and round-trips one command E2E through
|
||||
the real relay-node (extend the `e2e/harness` pattern with the real `WebSocketLike` adapter).
|
||||
|
||||
## Explicitly NOT in Phase 0
|
||||
Postgres/Redis (in-memory only), real KMS (dev in-process signer), wildcard TLS/multi-tenant subdomain
|
||||
routing, horizontal scaling, F6 replay-epoch transport (preview stays inert), metering. Those are
|
||||
Phase 1/2 in DEPLOY_RELAY.md.
|
||||
|
||||
## Security notes (keep even in dev)
|
||||
- Real Origin/CSWSH check on the WSS upgrade (don’t stub it off for localhost — set allowedOrigins to
|
||||
the dev origin). Real capability-token verify + DPoP (no bypass). Self-signed certs are dev-only;
|
||||
never reuse the dev CA anywhere real. hostContentSecret 0600, never logged.
|
||||
Reference in New Issue
Block a user