From bb738058e6ca033e9ca5ad56a9c2b49a06f8cd53 Mon Sep 17 00:00:00 2001 From: Rai Butera Date: Sat, 14 Mar 2026 15:27:15 +0000 Subject: [PATCH] fix(gateway): keep bootstrap backend connects in pairing --- .../server/ws-connection/connect-policy.test.ts | 10 +++++----- src/gateway/server/ws-connection/connect-policy.ts | 12 ++++++------ 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/gateway/server/ws-connection/connect-policy.test.ts b/src/gateway/server/ws-connection/connect-policy.test.ts index ff6ccc9f5e9..51e1b649126 100644 --- a/src/gateway/server/ws-connection/connect-policy.test.ts +++ b/src/gateway/server/ws-connection/connect-policy.test.ts @@ -524,8 +524,8 @@ describe("ws connect policy", () => { }), ).toBe(false); - // bootstrap-token should also count as a trusted backend authOk method so - // first-time paired sessions can still use internal inter_session delivery. + // bootstrap-token is onboarding-only auth: first-time backend connects must still + // go through pairing so the session can mint/persist a device token. expect( shouldSkipBackendSelfPairing({ connectParams: makeConnectParams( @@ -538,7 +538,7 @@ describe("ws connect policy", () => { authOk: true, authMethod: "bootstrap-token", }), - ).toBe(true); + ).toBe(false); // Remote device-token backend client is trusted when authOk=true. expect( @@ -555,7 +555,7 @@ describe("ws connect policy", () => { }), ).toBe(true); - // Remote bootstrap-token backend client is trusted when authOk=true. + // Remote bootstrap-token backend clients are also still onboarding and must pair. expect( shouldSkipBackendSelfPairing({ connectParams: makeConnectParams( @@ -568,7 +568,7 @@ describe("ws connect policy", () => { authOk: true, authMethod: "bootstrap-token", }), - ).toBe(true); + ).toBe(false); // Remote backend client (gateway.mode=remote) with valid shared-secret auth is trusted. expect( diff --git a/src/gateway/server/ws-connection/connect-policy.ts b/src/gateway/server/ws-connection/connect-policy.ts index 0ad8a54757a..b12f2f051d0 100644 --- a/src/gateway/server/ws-connection/connect-policy.ts +++ b/src/gateway/server/ws-connection/connect-policy.ts @@ -93,13 +93,13 @@ export function shouldSkipBackendSelfPairing(params: { } // token/password: sharedAuthOk is set specifically for these in auth-context.ts. const usesSharedSecretAuth = params.authMethod === "token" || params.authMethod === "password"; - // device-token, tailscale, and bootstrap-token: all are valid auth methods but - // sharedAuthOk is never set for them in the WS flow (auth-context.ts only sets it for - // token/password/trusted-proxy). Gate on authOk directly for these instead. + // device-token and tailscale are valid backend auth methods, but sharedAuthOk is never + // set for them in the WS flow (auth-context.ts only sets it for token/password/ + // trusted-proxy). Gate on authOk directly for these instead. + // bootstrap-token is intentionally excluded: first-time bootstrap connects must still + // complete pairing so the gateway can mint and persist a device token. const usesAuthOkMethod = - params.authMethod === "device-token" || - params.authMethod === "tailscale" || - params.authMethod === "bootstrap-token"; + params.authMethod === "device-token" || params.authMethod === "tailscale"; // When auth is disabled entirely (mode="none"), there is no credential to verify. Restrict to // local connections only — remote + no-auth would be a security hole. const authIsDisabled = params.authMethod === "none";