/** * Unit tests for `resolveWorkspaceToken` — the security-critical * helper that returns the plaintext Smartsheet API token for a brand. * * Every async export of a "use server" file is reachable as a server * action RPC, so this helper was extracted to a plain server-only * module (cycle 7) precisely to prevent accidental client exposure. * The 4-branch discriminated union below is the security boundary — * if it ever leaks or collapses, tokens can leak. */ import { describe, it, expect, vi, beforeEach } from "vitest"; const { mockWithBrand, mockDecryptToken } = vi.hoisted(() => ({ mockWithBrand: vi.fn(), mockDecryptToken: vi.fn(), })); // Stub the server-only guard so the module can be imported under vitest. vi.mock("server-only", () => ({})); // Mock the Drizzle client wrapper so we can simulate per-brand reads // without hitting Postgres. vi.mock("@/db/client", () => ({ withBrand: mockWithBrand, })); // Mock the AES-256-GCM decryption layer so we can simulate bad // ciphertext without managing real keys / IVs. vi.mock("@/lib/crypto", () => ({ decryptToken: mockDecryptToken, })); import { resolveWorkspaceToken } from "@/services/workspace-token"; beforeEach(() => { mockWithBrand.mockReset(); mockDecryptToken.mockReset(); }); describe("resolveWorkspaceToken", () => { it("returns ok:true with the plaintext token when the workspace exists, is enabled, and decrypts", async () => { mockWithBrand.mockImplementationOnce( async (_brandId: string, fn: (db: unknown) => Promise) => fn({ select: () => ({ from: () => ({ where: () => ({ limit: () => [ { brandId: "brand-1", encryptedApiToken: "cipher", tokenIv: "iv", tokenAuthTag: "tag", connectionEnabled: true, }, ], }), }), }), }), ); mockDecryptToken.mockReturnValueOnce("plain-token-abc"); const result = await resolveWorkspaceToken("brand-1"); expect(result).toEqual({ ok: true, token: "plain-token-abc" }); expect(mockDecryptToken).toHaveBeenCalledWith({ cipher: "cipher", iv: "iv", authTag: "tag", }); }); it("returns ok:false reason:no_workspace when the workspace row does not exist", async () => { mockWithBrand.mockImplementationOnce( async (_brandId: string, fn: (db: unknown) => Promise) => fn({ select: () => ({ from: () => ({ where: () => ({ limit: () => [], }), }), }), }), ); const result = await resolveWorkspaceToken("brand-1"); expect(result).toEqual({ ok: false, reason: "no_workspace" }); expect(mockDecryptToken).not.toHaveBeenCalled(); }); it("returns ok:false reason:connection_disabled when the workspace is paused", async () => { mockWithBrand.mockImplementationOnce( async (_brandId: string, fn: (db: unknown) => Promise) => fn({ select: () => ({ from: () => ({ where: () => ({ limit: () => [ { brandId: "brand-1", encryptedApiToken: "cipher", tokenIv: "iv", tokenAuthTag: "tag", connectionEnabled: false, }, ], }), }), }), }), ); const result = await resolveWorkspaceToken("brand-1"); expect(result).toEqual({ ok: false, reason: "connection_disabled" }); expect(mockDecryptToken).not.toHaveBeenCalled(); }); it("returns ok:false reason:decryption_failed with the underlying error message", async () => { mockWithBrand.mockImplementationOnce( async (_brandId: string, fn: (db: unknown) => Promise) => fn({ select: () => ({ from: () => ({ where: () => ({ limit: () => [ { brandId: "brand-1", encryptedApiToken: "cipher", tokenIv: "iv", tokenAuthTag: "tag", connectionEnabled: true, }, ], }), }), }), }), ); mockDecryptToken.mockImplementationOnce(() => { throw new Error("Unsupported state or unable to authenticate data"); }); const result = await resolveWorkspaceToken("brand-1"); expect(result).toEqual({ ok: false, reason: "decryption_failed", error: "Unsupported state or unable to authenticate data", }); }); it("wraps non-Error thrown values in a string for decryption_failed", async () => { mockWithBrand.mockImplementationOnce( async (_brandId: string, fn: (db: unknown) => Promise) => fn({ select: () => ({ from: () => ({ where: () => ({ limit: () => [ { brandId: "brand-1", encryptedApiToken: "cipher", tokenIv: "iv", tokenAuthTag: "tag", connectionEnabled: true, }, ], }), }), }), }), ); mockDecryptToken.mockImplementationOnce(() => { throw "string-throw-not-error"; }); const result = await resolveWorkspaceToken("brand-1"); expect(result).toEqual({ ok: false, reason: "decryption_failed", error: "string-throw-not-error", }); }); it("threads the brandId through to withBrand", async () => { mockWithBrand.mockImplementationOnce( async (_brandId: string, fn: (db: unknown) => Promise) => fn({ select: () => ({ from: () => ({ where: () => ({ limit: () => [], }), }), }), }), ); await resolveWorkspaceToken("the-right-brand"); expect(mockWithBrand).toHaveBeenCalledWith( "the-right-brand", expect.any(Function), ); }); });