feat(relay): Phase1 waves A2-E — server entry, shared-store data plane, agent runtime, deploy artifacts
RELAY-PHASE1 Wave A2/B/C/D/E (12-agent workflow, all tsc-clean, 314/314 tests pass): - A2: control-plane server.ts entry + boot/redis.ts revocation-bus wiring + start script. - B1: relay-run shared-store EnforceDeps (relay-auth ports over the SAME Postgres+Redis as P3). - B2: registry-backed MtlsVerifier (verifyAgentCert, fail-closed, INV14). - B3: store-backed RouteResolver (subdomain->hostId). - B4: Redis relay:revocations subscriber -> tunnel teardown (INV12). - B5: main-phase1.ts production entry (public bind, real TLS, async-mTLS prefetch bridge) + staging /auth/mint. - B6 (PARTIAL): relay-web operator login + browser DPoP; proof offered via term.dpop.<b64u> subprotocol. - C: agent dist/cli.js build (esbuild) + runTunnel run-loop + CliDeps. - D1: same-origin static serve of relay-web/public from the browser WSS. - E: systemd units + gen-ca/gen-capability-key/issue-tls-cert scripts + deploy/RUNBOOK.md. Adversarial review: all hard invariants PASS. Follow-ups (B7): close DPoP-subprotocol read on browser-server (blocks browser connect); rate-limit /auth/mint (F1); wire activeSessionCount (F2); scrub error logs (F5). Excludes unrelated public/style.css (concurrent iOS job).
This commit is contained in:
@@ -1,11 +1,37 @@
|
||||
/**
|
||||
* index.html entry — v0.8 password gate → terminal view over the passthrough transport.
|
||||
* No inline script (strict-CSP friendly): this bundle is loaded via <script type="module">.
|
||||
* index.html entry — Phase-1 STAGING operator login → terminal view.
|
||||
*
|
||||
* The deployed Phase-1 relay serves this bundle and enables `POST /auth/mint` (B5). Flow:
|
||||
* password → mint a §4.3 capability token bound to a fresh browser DPoP key → open the WS carrying
|
||||
* the token (+ a DPoP proof signed by the SAME key) via the subprotocol → drive the terminal view.
|
||||
* No inline script (strict-CSP friendly): loaded via <script type="module">.
|
||||
*/
|
||||
import { readConfig } from '../config'
|
||||
import { mountPasswordLogin } from '../login-password'
|
||||
import { readConfig, type RelayWebConfig } from '../config'
|
||||
import { mountStagingLogin, type StagingSession } from '../login-staging'
|
||||
import { createPassthroughTransport } from '../ws-transport'
|
||||
import { mountTerminalView } from '../terminal-view'
|
||||
import { DPOP_HTM, htuFor } from '../dpop'
|
||||
|
||||
async function connect(
|
||||
cfg: RelayWebConfig,
|
||||
session: StagingSession,
|
||||
loginRoot: HTMLElement,
|
||||
termRoot: HTMLElement,
|
||||
): Promise<void> {
|
||||
// Sign a fresh DPoP proof for THIS upgrade with the key the token binds (`cnf.jkt`).
|
||||
const nowSec = Math.floor(Date.now() / 1000)
|
||||
const dpopProof = await session.dpop.proof(htuFor(session.aud), DPOP_HTM, nowSec)
|
||||
|
||||
const transport = createPassthroughTransport(cfg, {
|
||||
capabilityToken: session.token,
|
||||
dpopProof,
|
||||
})
|
||||
// Reveal the terminal only after the socket is open; on failure the login screen stays visible.
|
||||
await transport.open()
|
||||
loginRoot.hidden = true
|
||||
termRoot.hidden = false
|
||||
mountTerminalView(termRoot, transport)
|
||||
}
|
||||
|
||||
function boot(): void {
|
||||
const cfg = readConfig(window.location)
|
||||
@@ -13,12 +39,13 @@ function boot(): void {
|
||||
const termRoot = document.getElementById('terminal')
|
||||
if (!loginRoot || !termRoot) return
|
||||
|
||||
mountPasswordLogin(loginRoot, cfg, {
|
||||
onSuccess: () => {
|
||||
loginRoot.hidden = true
|
||||
termRoot.hidden = false
|
||||
const transport = createPassthroughTransport(cfg)
|
||||
void transport.open().then(() => mountTerminalView(termRoot, transport))
|
||||
mountStagingLogin(loginRoot, cfg, {
|
||||
onSuccess: (session) => {
|
||||
void connect(cfg, session, loginRoot, termRoot).catch(() => {
|
||||
// Connection denied/dropped — keep the operator on the login screen (no bearer in logs).
|
||||
loginRoot.hidden = false
|
||||
termRoot.hidden = true
|
||||
})
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user