feat(relay): Phase1 foundation — P3 Postgres store + async capability verifier + compose
RELAY-PHASE1 Wave A (2/3) + E1 infra: - A1: createPgStores() Postgres adapter for all 9 P3 store ports + runMigrations(); writable-CTE atomic INV8 status swaps; 0002_routes.sql. 23/23 pg tests, 96.72% cov. - A3: real capability verifier delegating to relay-auth verifyCapabilityToken; sync->async seam across authz/provision/main. Full CP suite 15 files/101 pass, tsc clean. - E1: deploy/docker-compose.yml (Postgres16+Redis7, loopback-only) + .env.example. - docs: PLAN_RELAY_PHASE1.md file-level execution spec; PROGRESS_LOG RELAY-PHASE1 section.
This commit is contained in:
38
control-plane/src/boot/verifier.ts
Normal file
38
control-plane/src/boot/verifier.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* A3 — REAL capability verifier, backed by relay-auth's `verifyCapabilityToken` (P5). Replaces the
|
||||
* fail-closed `refuseAllVerifier` stub. The frozen §4.3 verify signature is ASYNC (Ed25519 verify
|
||||
* over WebCrypto) and reads its verifying key from relay-auth's startup registry (config/keys.ts),
|
||||
* never as a parameter — so we (a) adapt it to the async `CapabilityVerifier` seam and (b) load the
|
||||
* key at boot from the CP env's already-validated pubkey.
|
||||
*
|
||||
* KEY BRIDGE (INV9): the CP env var is `CAPABILITY_SIGN_PUBKEY_B64` (base64), parsed+validated in
|
||||
* `env.ts` to `env.capabilitySignPubkey` (32 raw Ed25519 bytes). relay-auth's own env loader expects
|
||||
* a DIFFERENT var name (`RELAY_AUTH_VERIFY_PUBKEY`, base64url), so we do NOT use it — we import the
|
||||
* 32 raw bytes to a non-exportable verify-only CryptoKey via WebCrypto and call relay-auth's
|
||||
* `configureVerifyKey(CryptoKey)` directly.
|
||||
*/
|
||||
import { verifyCapabilityToken, configureVerifyKey } from 'relay-auth'
|
||||
import type { CapabilityToken } from 'relay-contracts'
|
||||
import type { CapabilityVerifier } from '../api/authz.js'
|
||||
|
||||
/** The real verifier: delegates verbatim to P5's frozen §4.3 `verifyCapabilityToken`. */
|
||||
export function createCapabilityVerifier(): CapabilityVerifier {
|
||||
return {
|
||||
verify(raw: string, expectedAud: string, now: number): Promise<CapabilityToken> {
|
||||
return verifyCapabilityToken(raw, expectedAud, now)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the §4.3 verifying key into relay-auth's startup registry from the CP env's raw 32-byte
|
||||
* Ed25519 public key (`env.capabilitySignPubkey`). Non-exportable, `verify`-only. Must run before
|
||||
* the real verifier serves any request, else `verifyCapabilityToken` throws `KeyConfigError`.
|
||||
*/
|
||||
export async function configureCapabilityVerifyKey(pubkeyRaw: Uint8Array): Promise<void> {
|
||||
// Copy into a fresh ArrayBuffer-backed view (WebCrypto's BufferSource typing / no shared pool).
|
||||
const bytes = new Uint8Array(pubkeyRaw.length)
|
||||
bytes.set(pubkeyRaw)
|
||||
const key = await globalThis.crypto.subtle.importKey('raw', bytes, { name: 'Ed25519' }, false, ['verify'])
|
||||
configureVerifyKey(key)
|
||||
}
|
||||
Reference in New Issue
Block a user