From 8cd0abf76acd830bd96b5b7df2f266e2f4480fb3 Mon Sep 17 00:00:00 2001 From: Jinwoo Hong <73622457+Jinwoo-H@users.noreply.github.com> Date: Mon, 7 Sep 2026 07:39:38 -0400 Subject: [PATCH] test(relay): prove the capability header reaches acceptControl over a real upgrade (#19274) The unit tests cover parseRelayHostCapabilities, the sendHelloAck gating, and the header literal separately, but nothing joined them: a typo in the header name read off the upgrade request passed the entire suite. This drives a real control upgrade carrying the header, leaves an invite connection pending, and asserts the rebound control's ack. Renaming the header the server reads fails it. --- cloud/apps/relay/src/relay.blackbox.test.ts | 75 ++++++++++++++++++++- 1 file changed, 73 insertions(+), 2 deletions(-) diff --git a/cloud/apps/relay/src/relay.blackbox.test.ts b/cloud/apps/relay/src/relay.blackbox.test.ts index 38134213e76..0202d964ee7 100644 --- a/cloud/apps/relay/src/relay.blackbox.test.ts +++ b/cloud/apps/relay/src/relay.blackbox.test.ts @@ -9,7 +9,9 @@ import { fileURLToPath } from 'node:url' import { exportJWK, generateKeyPair, jwtVerify, SignJWT } from 'jose' import { buildHostProofMacInput, - HOST_CHALLENGE_PLAINTEXT_DOMAIN + HOST_CHALLENGE_PLAINTEXT_DOMAIN, + RELAY_HOST_CAPABILITIES_HEADER, + RELAY_HOST_CAPABILITY_PENDING_CONN_DETAILS } from '@orca-cloud/relay-contract' import nacl from 'tweetnacl' import { afterAll, beforeAll, describe, expect, it } from 'vitest' @@ -282,11 +284,17 @@ async function openHostControl(input?: { previousGeneration?: number keyPair?: nacl.BoxKeyPair assignmentEpoch?: number + capabilities?: string }): Promise<{ socket: WebSocket; ack: Record; keyPair: nacl.BoxKeyPair }> { const keyPair = input?.keyPair ?? nacl.box.keyPair() const hostId = createHash('sha256').update(keyPair.publicKey).digest('base64url').slice(0, 16) const socket = new WebSocket(`${relayUrl.replace('http:', 'ws:')}/v1/host/control`, { - headers: { authorization: `Bearer ${await relayToken('orca-relay', hostId)}` }, + headers: { + authorization: `Bearer ${await relayToken('orca-relay', hostId)}`, + ...(input?.capabilities + ? { [RELAY_HOST_CAPABILITIES_HEADER]: input.capabilities } + : {}) + }, perMessageDeflate: false }) await new Promise((resolveOpen, reject) => { @@ -653,6 +661,69 @@ describe('served relay URL', () => { expect(result.reason).not.toContain('http') }) + it('restates a pending connection to the rebound control, detailed only when advertised', async () => { + // The one link the unit tests cannot reach: an upgrade that really carries + // x-orca-host-capabilities must reach acceptControl and change the ack. A + // typo in the header name here passes every other test in the suite. + const host = await openHostControl() + const hostId = createHash('sha256') + .update(host.keyPair.publicKey) + .digest('base64url') + .slice(0, 16) + const inviteResponse = nextMessage(host.socket) + host.socket.send( + JSON.stringify({ + type: 'invite-create', + reqId: 'capability-invite', + relayDeviceId: 'capability-device' + }) + ) + const invite = await inviteResponse + const phone = new WebSocket(`${relayUrl.replace('http:', 'ws:')}/v1/connect/${hostId}`, { + headers: forwardedHeaders() + }) + await new Promise((resolveOpen, reject) => { + phone.once('open', resolveOpen) + phone.once('error', reject) + }) + const connectionPromise = nextMessage(host.socket) + phone.send( + JSON.stringify({ type: 'relay-auth', v: 1, mode: 'connect', credential: invite.inviteToken }) + ) + // Never attached: the connection stays pending, which is what the ack restates. + const connection = await connectionPromise + expect(connection.type).toBe('conn-open') + + const capable = await openHostControl({ + keyPair: host.keyPair, + controlResumeSecret: String(host.ack.controlResumeSecret), + previousGeneration: 1, + capabilities: RELAY_HOST_CAPABILITY_PENDING_CONN_DETAILS + }) + expect(capable.ack.pendingConns).toEqual([ + { + connId: connection.connId, + connTicket: connection.connTicket, + kind: 'invite', + relayDeviceId: 'capability-device' + } + ]) + + const legacy = await openHostControl({ + keyPair: host.keyPair, + controlResumeSecret: String(capable.ack.controlResumeSecret), + previousGeneration: 1 + }) + // A shipped host parses these entries strictly, so an unannounced key would + // fail the whole ack and kill a control that was working. + expect(legacy.ack.pendingConns).toEqual([ + { connId: connection.connId, connTicket: connection.connTicket } + ]) + + phone.close() + legacy.socket.close() + }) + it('keeps a pending attach usable after a bad ticket and rejects ticket replay', async () => { const host = await openHostControl() const hostId = createHash('sha256')