fix(signal): guard hosted device linking

Co-authored-by: jesse-merhi <79823012+jesse-merhi@users.noreply.github.com>
This commit is contained in:
roboclaw-bot
2026-08-19 01:02:18 +00:00
parent bfdde201ee
commit f8533ffeb3
2 changed files with 22 additions and 1 deletions
@@ -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: {} },
+2 -1
View File
@@ -112,7 +112,7 @@ async function prepareManagedSignalLink(params: {
accountId: string;
runtime: RuntimeEnv;
prompter: WizardPrompter;
options?: { signal?: AbortSignal };
options?: { signal?: AbortSignal; beforePersistentEffect?: () => Promise<void> };
cliPath: string;
}): Promise<string | undefined> {
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();