

























@@ -169,6 +169,83 @@ async function applyCurrentConfig(ws: WebSocket) {
169169});
170170}
171171172+async function expectGatewayAuthChangedClose(closed: ReturnType<typeof waitForGatewayWsClose>) {
173+await expect(closed).resolves.toEqual({
174+code: 4001,
175+reason: "gateway auth changed",
176+});
177+}
178+179+async function resolveRequiredSharedGatewayGeneration() {
180+const { resolveSharedGatewaySessionGeneration } =
181+await import("./server/ws-shared-generation.js");
182+const issuerGeneration = resolveSharedGatewaySessionGeneration({
183+mode: "token",
184+token: OLD_TOKEN,
185+allowTailscale: false,
186+});
187+expect(issuerGeneration).toBeTypeOf("string");
188+if (!issuerGeneration) {
189+throw new Error("expected shared gateway generation");
190+}
191+return issuerGeneration;
192+}
193+194+function requireHelloDeviceToken(
195+hello: Awaited<ReturnType<typeof openDeviceTokenWsWithDetails>>["hello"],
196+) {
197+const helloDeviceToken = hello.auth?.deviceToken;
198+if (typeof helloDeviceToken !== "string") {
199+throw new Error("expected hello device token");
200+}
201+return helloDeviceToken;
202+}
203+204+async function expectIssuerTaggedDeviceToken(params: {
205+deviceId: string;
206+token: string;
207+issuerGeneration: string;
208+}) {
209+const { getPairedDevice, verifyDeviceToken } = await import("../infra/device-pairing.js");
210+const paired = await getPairedDevice(params.deviceId);
211+expect(paired?.tokens?.operator?.issuer).toEqual({
212+kind: "shared-gateway-auth",
213+generation: params.issuerGeneration,
214+});
215+await expect(
216+verifyDeviceToken({
217+deviceId: params.deviceId,
218+token: params.token,
219+role: "operator",
220+scopes: ["operator.admin"],
221+requiredSharedGatewaySessionGeneration: params.issuerGeneration,
222+}),
223+).resolves.toEqual({
224+ok: true,
225+issuer: {
226+kind: "shared-gateway-auth",
227+generation: params.issuerGeneration,
228+},
229+});
230+}
231+232+async function expectIssuerMetadataPreservedOnReconnect(params: { browserClient?: boolean } = {}) {
233+const issuerGeneration = await resolveRequiredSharedGatewayGeneration();
234+const { ws, deviceId, hello } = await openDeviceTokenWsWithDetails({
235+ issuerGeneration,
236+browserClient: params.browserClient,
237+});
238+try {
239+await expectIssuerTaggedDeviceToken({
240+ deviceId,
241+token: requireHelloDeviceToken(hello),
242+ issuerGeneration,
243+});
244+} finally {
245+await closeWsAndWait(ws);
246+}
247+}
248+172249describe("gateway shared auth rotation", () => {
173250let server: Awaited<ReturnType<typeof startGatewayServer>>;
174251let sharedTokenRotationCase: {
@@ -225,17 +302,7 @@ describe("gateway shared auth rotation", () => {
225302});
226303227304it("disconnects issuer-tagged device-token websocket sessions after shared token rotation", async () => {
228-const { resolveSharedGatewaySessionGeneration } =
229-await import("./server/ws-shared-generation.js");
230-const issuerGeneration = resolveSharedGatewaySessionGeneration({
231-mode: "token",
232-token: OLD_TOKEN,
233-allowTailscale: false,
234-});
235-expect(issuerGeneration).toBeTypeOf("string");
236-if (!issuerGeneration) {
237-throw new Error("expected shared gateway generation");
238-}
305+const issuerGeneration = await resolveRequiredSharedGatewayGeneration();
239306const ws = await openDeviceTokenWs({
240307 issuerGeneration,
241308});
@@ -244,106 +311,18 @@ describe("gateway shared auth rotation", () => {
244311const res = await sendSharedTokenRotationPatch(ws);
245312246313expect(res.ok).toBe(true);
247-await expect(closed).resolves.toEqual({
248-code: 4001,
249-reason: "gateway auth changed",
250-});
314+await expectGatewayAuthChangedClose(closed);
251315} finally {
252316await closeWsAndWait(ws);
253317}
254318});
255319256320it("preserves issuer-tagged browser device tokens on reconnect", async () => {
257-const { getPairedDevice, verifyDeviceToken } = await import("../infra/device-pairing.js");
258-const { resolveSharedGatewaySessionGeneration } =
259-await import("./server/ws-shared-generation.js");
260-const issuerGeneration = resolveSharedGatewaySessionGeneration({
261-mode: "token",
262-token: OLD_TOKEN,
263-allowTailscale: false,
264-});
265-expect(issuerGeneration).toBeTypeOf("string");
266-if (!issuerGeneration) {
267-throw new Error("expected shared gateway generation");
268-}
269-const { ws, deviceId, hello } = await openDeviceTokenWsWithDetails({
270- issuerGeneration,
271-browserClient: true,
272-});
273-try {
274-const helloDeviceToken = hello.auth?.deviceToken;
275-if (typeof helloDeviceToken !== "string") {
276-throw new Error("expected hello device token");
277-}
278-const paired = await getPairedDevice(deviceId);
279-expect(paired?.tokens?.operator?.issuer).toEqual({
280-kind: "shared-gateway-auth",
281-generation: issuerGeneration,
282-});
283-await expect(
284-verifyDeviceToken({
285- deviceId,
286-token: helloDeviceToken,
287-role: "operator",
288-scopes: ["operator.admin"],
289-requiredSharedGatewaySessionGeneration: issuerGeneration,
290-}),
291-).resolves.toEqual({
292-ok: true,
293-issuer: {
294-kind: "shared-gateway-auth",
295-generation: issuerGeneration,
296-},
297-});
298-} finally {
299-await closeWsAndWait(ws);
300-}
321+await expectIssuerMetadataPreservedOnReconnect({ browserClient: true });
301322});
302323303324it("keeps issuer metadata when tagged device tokens reconnect through non-browser clients", async () => {
304-const { getPairedDevice, verifyDeviceToken } = await import("../infra/device-pairing.js");
305-const { resolveSharedGatewaySessionGeneration } =
306-await import("./server/ws-shared-generation.js");
307-const issuerGeneration = resolveSharedGatewaySessionGeneration({
308-mode: "token",
309-token: OLD_TOKEN,
310-allowTailscale: false,
311-});
312-expect(issuerGeneration).toBeTypeOf("string");
313-if (!issuerGeneration) {
314-throw new Error("expected shared gateway generation");
315-}
316-const { ws, deviceId, hello } = await openDeviceTokenWsWithDetails({
317- issuerGeneration,
318-});
319-try {
320-const helloDeviceToken = hello.auth?.deviceToken;
321-if (typeof helloDeviceToken !== "string") {
322-throw new Error("expected hello device token");
323-}
324-const paired = await getPairedDevice(deviceId);
325-expect(paired?.tokens?.operator?.issuer).toEqual({
326-kind: "shared-gateway-auth",
327-generation: issuerGeneration,
328-});
329-await expect(
330-verifyDeviceToken({
331- deviceId,
332-token: helloDeviceToken,
333-role: "operator",
334-scopes: ["operator.admin"],
335-requiredSharedGatewaySessionGeneration: issuerGeneration,
336-}),
337-).resolves.toEqual({
338-ok: true,
339-issuer: {
340-kind: "shared-gateway-auth",
341-generation: issuerGeneration,
342-},
343-});
344-} finally {
345-await closeWsAndWait(ws);
346-}
325+await expectIssuerMetadataPreservedOnReconnect();
347326});
348327});
349328@@ -401,10 +380,7 @@ describe("gateway shared auth rotation with unchanged SecretRefs", () => {
401380process.env[SECRET_REF_TOKEN_ID] = NEW_TOKEN;
402381const res = await applyCurrentConfig(ws);
403382expect(res.ok).toBe(true);
404-await expect(closed).resolves.toEqual({
405-code: 4001,
406-reason: "gateway auth changed",
407-});
383+await expectGatewayAuthChangedClose(closed);
408384} finally {
409385await closeWsAndWait(ws);
410386}
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。