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:
32
control-plane/src/boot/redis.ts
Normal file
32
control-plane/src/boot/redis.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* A2 — ioredis client + `RedisPublisher` adapter for the P3 server entrypoint.
|
||||
*
|
||||
* `createRedisClient(url)` constructs the single ioredis connection used for the revocation-bus
|
||||
* PUBLISH side (the FROZEN `relay:revocations` channel; P1 nodes subscribe — see routing/bus.ts).
|
||||
* `createRedisPublisher` narrows that client to the minimal `RedisPublisher` surface
|
||||
* `createRedisRevocationBus` consumes, so the concrete ioredis type never leaks into the bus wiring
|
||||
* and the seam stays unit-testable with a fake. INV9: no secrets pass through here — the URL is
|
||||
* owned/validated by `loadEnv` and never logged.
|
||||
*/
|
||||
// The default export IS `Redis`; imported by name because this package's tsconfig has no
|
||||
// `esModuleInterop`, under which a default import of the CJS module resolves to its namespace.
|
||||
import { Redis } from 'ioredis'
|
||||
import type { RedisPublisher } from '../routing/bus.js'
|
||||
|
||||
/**
|
||||
* Construct the production ioredis client from a validated connection URL. Connection lifecycle
|
||||
* (connect/retry) is managed by ioredis; the caller owns `quit()` on shutdown.
|
||||
*/
|
||||
export function createRedisClient(url: string): Redis {
|
||||
return new Redis(url)
|
||||
}
|
||||
|
||||
/**
|
||||
* Adapt an ioredis client to the `RedisPublisher` seam. Forwards `publish(channel, message)`
|
||||
* verbatim and returns the subscriber count the driver reports (Promise<number>).
|
||||
*/
|
||||
export function createRedisPublisher(redis: Redis): RedisPublisher {
|
||||
return {
|
||||
publish: (channel: string, message: string): Promise<number> => redis.publish(channel, message),
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user