diff --git a/extensions/signal/src/setup-surface.test.ts b/extensions/signal/src/setup-surface.test.ts index 09e3638517c4..c9e50cc23532 100644 --- a/extensions/signal/src/setup-surface.test.ts +++ b/extensions/signal/src/setup-surface.test.ts @@ -186,6 +186,26 @@ describe("Signal hosted setup linking", () => { expect(result?.credentialValues?.signalNumber).toBe("+15555550125"); }); + it("rejects stale hosted authority before starting device linking", async () => { + const guardError = new Error("verified inference changed"); + const beforePersistentEffect = vi.fn(async () => { + throw guardError; + }); + const prompt = createPrompter(); + + await expect( + prepareSignal({ + prompter: prompt.prompter, + beforePersistentEffect, + }), + ).rejects.toBe(guardError); + + expect(beforePersistentEffect).toHaveBeenCalledOnce(); + expect(mocks.spawnDaemon).not.toHaveBeenCalled(); + expect(mocks.rpc).not.toHaveBeenCalled(); + expect(prompt.qrCode).not.toHaveBeenCalled(); + }); + it.each([ { label: "without QR support", includeSignal: true, includeQr: false, cfg: {} }, { label: "without hosted cancellation", includeSignal: false, includeQr: true, cfg: {} }, diff --git a/extensions/signal/src/setup-surface.ts b/extensions/signal/src/setup-surface.ts index 161825dbf270..e39b8338482b 100644 --- a/extensions/signal/src/setup-surface.ts +++ b/extensions/signal/src/setup-surface.ts @@ -112,7 +112,7 @@ async function prepareManagedSignalLink(params: { accountId: string; runtime: RuntimeEnv; prompter: WizardPrompter; - options?: { signal?: AbortSignal }; + options?: { signal?: AbortSignal; beforePersistentEffect?: () => Promise }; cliPath: string; }): Promise { const signal = params.options?.signal; @@ -133,6 +133,7 @@ async function prepareManagedSignalLink(params: { return undefined; } + await params.options?.beforePersistentEffect?.(); signal.throwIfAborted(); const lifecycle = createSignalDaemonLifecycle({ abortSignal: signal }); const onAbort = () => void lifecycle.stop();