From 76e03c04d50b35a0d483d9dd2c870bba594c76e7 Mon Sep 17 00:00:00 2001 From: Michael Yong Date: Fri, 11 Sep 2026 14:12:20 -0700 Subject: [PATCH] fix(connect): acknowledge retries of owned machine revocation --- apps/web/src/server/api.test.ts | 47 +++++++++++++++++++++++++++++++++ apps/web/src/server/api.ts | 1 - 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/apps/web/src/server/api.test.ts b/apps/web/src/server/api.test.ts index 601e157418..9a08f9cad4 100644 --- a/apps/web/src/server/api.test.ts +++ b/apps/web/src/server/api.test.ts @@ -589,6 +589,49 @@ describe("server-authenticated machine-code round trip", () => { db.select().from(machine).where(eq(machine.id, redeemed.machineId)).get() ?.revokedAt, ).not.toBeNull(); + const revokedAt = db.select().from(machine).get()?.revokedAt; + for (const token of [serverCredential, "bbcred_other"]) { + await expect( + revokeMachineForServerCredential(deps, token, redeemed.machineId), + ).resolves.toEqual({ ok: true }); + } + expect(db.select().from(machine).get()?.revokedAt).toEqual(revokedAt); + await expect( + revokeMachineForServerCredential(deps, serverCredential, "missing"), + ).resolves.toEqual({ error: "not-found", status: 404 }); + seedUser("foreign"); + db.insert(machine) + .values({ + id: "foreign-device", + userId: "foreign", + credentialHash: "foreign-hash", + createdAt: new Date(), + revokedAt: new Date(), + }) + .run(); + await expect( + revokeMachineForServerCredential( + deps, + serverCredential, + "foreign-device", + ), + ).resolves.toEqual({ error: "not-found", status: 404 }); + for (const token of ["", "bogus"]) { + await expect( + revokeMachineForServerCredential(deps, token, redeemed.machineId), + ).resolves.toEqual({ error: "unauthorized", status: 401 }); + } + db.update(server) + .set({ revokedAt: new Date() }) + .where(eq(server.id, target.server.id)) + .run(); + await expect( + revokeMachineForServerCredential( + deps, + serverCredential, + redeemed.machineId, + ), + ).resolves.toEqual({ error: "unauthorized", status: 401 }); await expect(redeemMachineCode(deps, minted.code)).resolves.toMatchObject({ error: "already-used", status: 409, @@ -652,6 +695,10 @@ describe("dashboard machine recovery", () => { expect(closeTunnel).toHaveBeenCalledWith("lost-laptop:lost-generation"); expect(closeTunnel).toHaveBeenCalledTimes(1); expect((await getAccountState(deps, "u1")).machines).toEqual([]); + await expect(revokeMachine(deps, "u1", "machine-owner")).resolves.toEqual({ + ok: true, + }); + expect(closeTunnel).toHaveBeenCalledTimes(1); expect( db.select().from(machine).where(eq(machine.id, "machine-owner")).get() ?.subdomain, diff --git a/apps/web/src/server/api.ts b/apps/web/src/server/api.ts index 6acec9e34a..b91c45563c 100644 --- a/apps/web/src/server/api.ts +++ b/apps/web/src/server/api.ts @@ -279,7 +279,6 @@ export async function revokeMachine( and(eq(labelClaim.kind, "machine"), eq(labelClaim.ownerId, machineId)), ) .get(); - if (!claim && existing.revokedAt !== null) return { error: "not-found" }; if (claim) { try {