Files
PaperClipAI/server/src/__tests__/cli-auth-routes.test.ts
T
DottaandPaperclip 2befcd9a0a Harden Board CLI approval and native verification fixtures (#16482)
Preserve governed Board CLI authority and strict verification fixtures on the Muse stack.

Keep approval/cancel ownership, current membership/key authority and durable first-change audit atomic. Bound Retry-After scheduling within the original challenge; never automatically resubmit consent. Retain descriptor ownership until identity-based cleanup and close it on success and error. Keep strict Git-origin and synchronized provider-entry fixture assertions.

Related public work: LukeAbell's existing PR #13919 proposes the same production descriptor-lifetime fix. This independently measured local integration retains the original tests and adds real-descriptor coverage. Do not treat this local integration as ownership of that contribution.

Carry actual merged UI source 896f3c7f3b through a normal forward merge, preserving canonical workspace recovery, Muse authority and existing migration bytes. Current-head CI and substantive review remain merge gates. Complete qualification of the final immutable canonical source and actual provider acceptance remain separate.

Refs #16482, #13919.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-17 23:22:57 -05:00

565 lines
24 KiB
TypeScript

import express from "express";
import request from "supertest";
import { beforeEach, describe, expect, it, vi } from "vitest";
import { createInviteRateLimiter, type InviteRateLimiter } from "../services/invite-rate-limit.js";
const mockAccessService = vi.hoisted(() => ({
isInstanceAdmin: vi.fn(),
hasPermission: vi.fn(),
canUser: vi.fn(),
}));
const mockAgentService = vi.hoisted(() => ({
getById: vi.fn(),
}));
const mockBoardAuthService = vi.hoisted(() => ({
createCliAuthChallenge: vi.fn(),
describeCliAuthChallenge: vi.fn(),
approveCliAuthChallenge: vi.fn(),
cancelCliAuthChallenge: vi.fn(),
resolveBoardAccess: vi.fn(),
resolveBoardActivityCompanyIds: vi.fn(),
assertCurrentBoardKey: vi.fn(),
revokeBoardApiKey: vi.fn(),
listBoardApiKeys: vi.fn(),
createNamedBoardApiKey: vi.fn(),
getBoardApiKeyForUser: vi.fn(),
}));
const mockLogActivity = vi.hoisted(() => vi.fn());
vi.mock("../services/index.js", () => ({
accessService: () => mockAccessService,
agentService: () => mockAgentService,
boardAuthService: () => mockBoardAuthService,
logActivity: mockLogActivity,
notifyHireApproved: vi.fn(),
deduplicateAgentName: vi.fn((name: string) => name),
}));
function registerModuleMocks() {
vi.doMock("../routes/authz.js", async () => vi.importActual("../routes/authz.js"));
vi.doMock("../services/index.js", () => ({
accessService: () => mockAccessService,
agentService: () => mockAgentService,
boardAuthService: () => mockBoardAuthService,
logActivity: mockLogActivity,
notifyHireApproved: vi.fn(),
deduplicateAgentName: vi.fn((name: string) => name),
}));
}
let appImportCounter = 0;
async function createApp(actor: any, db: any = {} as any, options: { cliAuthCreateRateLimiter?: InviteRateLimiter; cliAuthPollRateLimiter?: InviteRateLimiter } = {}) {
appImportCounter += 1;
const routeModulePath = `../routes/access.js?cli-auth-routes-${appImportCounter}`;
const middlewareModulePath = `../middleware/index.js?cli-auth-routes-${appImportCounter}`;
const [{ accessRoutes }, { errorHandler }] = await Promise.all([
import(routeModulePath) as Promise<typeof import("../routes/access.js")>,
import(middlewareModulePath) as Promise<typeof import("../middleware/index.js")>,
]);
const app = express();
app.use(express.json());
app.use((req, _res, next) => {
req.actor = {
...actor,
companyIds: Array.isArray(actor.companyIds) ? [...actor.companyIds] : actor.companyIds,
memberships: Array.isArray(actor.memberships)
? actor.memberships.map((membership: unknown) =>
typeof membership === "object" && membership !== null
? { ...membership }
: membership,
)
: actor.memberships,
};
next();
});
app.use(
"/api",
accessRoutes(db, {
deploymentMode: "authenticated",
deploymentExposure: "private",
bindHost: "127.0.0.1",
allowedHostnames: [],
...options,
}),
);
app.use(errorHandler);
return app;
}
describe("cli auth routes", () => {
beforeEach(async () => {
vi.resetModules();
vi.doUnmock("../services/index.js");
vi.doUnmock("../routes/authz.js");
vi.doUnmock("../routes/access.js");
vi.doUnmock("../middleware/index.js");
registerModuleMocks();
vi.resetAllMocks();
// Cold route transforms are fixture setup, not HTTP request latency.
// Use the hook budget while preserving the request tests' normal timeout.
await Promise.all([import("../routes/access.js"), import("../middleware/index.js")]);
});
it("creates a CLI auth challenge with approval metadata", async () => {
mockBoardAuthService.createCliAuthChallenge.mockResolvedValue({
challenge: {
id: "12345678-1234-4123-8123-123456789abc",
expiresAt: new Date("2026-03-23T13:00:00.000Z"),
},
challengeSecret: "pcp_cli_auth_secret",
pendingBoardToken: "pcp_board_token",
});
const app = await createApp({ type: "none", source: "none" });
const res = await request(app)
.post("/api/cli-auth/challenges")
.send({
command: "paperclipai company import",
clientName: "paperclipai cli",
requestedAccess: "board",
});
expect(res.status, res.text || JSON.stringify(res.body)).toBe(201);
expect(res.body).toMatchObject({
id: "12345678-1234-4123-8123-123456789abc",
token: "pcp_cli_auth_secret",
approvalPath: "/cli-auth/12345678-1234-4123-8123-123456789abc?token=pcp_cli_auth_secret",
pollPath: "/cli-auth/challenges/12345678-1234-4123-8123-123456789abc",
expiresAt: "2026-03-23T13:00:00.000Z",
});
expect(res.body.boardApiToken).toBe("pcp_board_token");
expect(res.body.approvalUrl).toContain("/cli-auth/12345678-1234-4123-8123-123456789abc?token=pcp_cli_auth_secret");
});
it("bounds anonymous create and poll independently without trusting spoofed forwarding headers", async () => {
let now = 1_000;
mockBoardAuthService.createCliAuthChallenge.mockResolvedValue({
challenge: { id: "12345678-1234-4123-8123-123456789abc", expiresAt: new Date(Date.now() + 60_000) },
challengeSecret: "pcp_cli_auth_secret", pendingBoardToken: "pcp_board_token",
});
mockBoardAuthService.describeCliAuthChallenge.mockResolvedValue({ id: "12345678-1234-4123-8123-123456789abc", status: "pending", requestedAccess: "board" });
const app = await createApp({ type: "none", source: "none" }, {}, {
cliAuthCreateRateLimiter: createInviteRateLimiter({ maxRequests: 2, now: () => now }),
cliAuthPollRateLimiter: createInviteRateLimiter({ maxRequests: 2, now: () => now }),
});
const payload = { command: "paperclipai auth login", requestedAccess: "board" };
for (let i = 0; i < 2; i++) expect((await request(app).post("/api/cli-auth/challenges").set("X-Forwarded-For", `198.51.100.${i}`).send(payload)).status).toBe(201);
const blocked = await request(app).post("/api/cli-auth/challenges").set("X-Forwarded-For", "203.0.113.7").send(payload);
expect(blocked.status).toBe(429);
expect(blocked.headers["retry-after"]).toBe("60");
expect(blocked.headers["cache-control"]).toBe("no-store");
expect(blocked.headers["referrer-policy"]).toBe("no-referrer");
expect(mockBoardAuthService.createCliAuthChallenge).toHaveBeenCalledTimes(2);
const path = "/api/cli-auth/challenges/12345678-1234-4123-8123-123456789abc?token=pcp_cli_auth_secret";
for (let i = 0; i < 2; i++) expect((await request(app).get(path).set("X-Forwarded-For", `198.51.100.${i}`)).status).toBe(200);
expect((await request(app).get(path).set("X-Forwarded-For", "203.0.113.8")).status).toBe(429);
expect(mockBoardAuthService.describeCliAuthChallenge).toHaveBeenCalledTimes(2);
now += 60_000;
expect((await request(app).post("/api/cli-auth/challenges").send(payload)).status).toBe(201);
expect((await request(app).get(path)).status).toBe(200);
});
it("preserves the normal one-second CLI poll cadence throughout the ten-minute challenge", async () => {
let now = Date.now();
vi.spyOn(Date, "now").mockImplementation(() => now);
mockBoardAuthService.describeCliAuthChallenge.mockResolvedValue({ id: "12345678-1234-4123-8123-123456789abc", status: "pending", requestedAccess: "board" });
const app = await createApp({ type: "none", source: "none" });
try {
for (let i = 0; i < 600; i++) {
const response = await request(app).get("/api/cli-auth/challenges/12345678-1234-4123-8123-123456789abc?token=pcp_cli_auth_secret");
expect(response.status).toBe(200);
expect(response.headers["x-ratelimit-limit"]).toBe("120");
now += 1_000;
}
} finally { vi.restoreAllMocks(); }
});
it("keeps challenge capabilities out of HTTP caches and referrers", async () => {
mockBoardAuthService.createCliAuthChallenge.mockResolvedValue({
challenge: { id: "12345678-1234-4123-8123-123456789abc", expiresAt: new Date(Date.now() + 60_000) },
challengeSecret: "pcp_cli_auth_secret", pendingBoardToken: "pcp_board_token",
});
mockBoardAuthService.describeCliAuthChallenge.mockResolvedValue({ id: "12345678-1234-4123-8123-123456789abc", status: "pending", requestedAccess: "board" });
const app = await createApp({ type: "none", source: "none" });
const responses = [
await request(app).post("/api/cli-auth/challenges").send({ command: "paperclipai auth login" }),
await request(app).get("/api/cli-auth/challenges/12345678-1234-4123-8123-123456789abc?token=pcp_cli_auth_secret"),
await request(app).get("/api/cli-auth/challenges/12345678-1234-4123-8123-123456789abc"),
await request(app).get("/api/cli-auth/challenges/not-a-uuid?token=pcp_cli_auth_secret"),
await request(app).post("/api/cli-auth/challenges/12345678-1234-4123-8123-123456789abc/approve").send({ token: "pcp_cli_auth_secret" }),
];
for (const response of responses) {
expect(response.headers["cache-control"]).toBe("no-store");
expect(response.headers["referrer-policy"]).toBe("no-referrer");
}
});
it("does not offer approval for an inaccessible requested organization", async () => {
mockBoardAuthService.describeCliAuthChallenge.mockResolvedValue({
id: "12345678-1234-4123-8123-123456789abc", status: "pending", requestedAccess: "board", requestedCompanyId: "company-private",
});
const app = await createApp({ type: "board", source: "session", userId: "user-1", companyIds: ["company-public"] });
const response = await request(app).get("/api/cli-auth/challenges/12345678-1234-4123-8123-123456789abc?token=pcp_cli_auth_secret");
expect(response.body.canApprove).toBe(false);
});
it("does not duplicate key-creation audit on a same-user approval retry", async () => {
mockBoardAuthService.approveCliAuthChallenge.mockResolvedValue({
status: "approved", created: false,
challenge: { id: "12345678-1234-4123-8123-123456789abc", boardApiKeyId: "board-key-1", requestedAccess: "board", expiresAt: new Date(Date.now() + 60_000) },
});
mockBoardAuthService.resolveBoardActivityCompanyIds.mockResolvedValue(["company-1"]);
const app = await createApp({ type: "board", source: "session", userId: "user-1" });
const response = await request(app).post("/api/cli-auth/challenges/12345678-1234-4123-8123-123456789abc/approve").send({ token: "pcp_cli_auth_secret" });
expect(response.status).toBe(200);
expect(response.body.approved).toBe(true);
expect(mockLogActivity).not.toHaveBeenCalled();
});
it("rejects anonymous access to generic skill documents", async () => {
const indexApp = await createApp({ type: "none", source: "none" });
const skillApp = await createApp({ type: "none", source: "none" });
const indexRes = await request(indexApp).get("/api/skills/index");
const skillRes = await request(skillApp).get("/api/skills/paperclip");
expect(indexRes.status, JSON.stringify(indexRes.body)).toBe(401);
expect(skillRes.status, skillRes.text || JSON.stringify(skillRes.body)).toBe(401);
});
it("serves the invite-scoped paperclip skill anonymously for active invites", async () => {
const invite = {
id: "invite-1",
companyId: "company-1",
inviteType: "company_join",
allowedJoinTypes: "agent",
tokenHash: "hash",
defaultsPayload: null,
expiresAt: new Date(Date.now() + 60_000),
invitedByUserId: null,
revokedAt: null,
acceptedAt: null,
createdAt: new Date(),
updatedAt: new Date(),
};
const db = {
select: vi.fn(() => ({
from: vi.fn(() => ({
where: vi.fn().mockResolvedValue([invite]),
})),
})),
};
const app = await createApp({ type: "none", source: "none" }, db);
const res = await request(app).get("/api/invites/token-123/skills/paperclip");
expect(res.status).toBe(200);
expect(res.headers["content-type"]).toContain("text/markdown");
expect(res.text).toContain("# Paperclip Skill");
});
it("marks challenge status as requiring sign-in for anonymous viewers", async () => {
mockBoardAuthService.describeCliAuthChallenge.mockResolvedValue({
id: "12345678-1234-4123-8123-123456789abc",
status: "pending",
command: "paperclipai company import",
clientName: "paperclipai cli",
requestedAccess: "board",
requestedCompanyId: null,
requestedCompanyName: null,
approvedAt: null,
cancelledAt: null,
expiresAt: "2026-03-23T13:00:00.000Z",
approvedByUser: null,
});
const app = await createApp({ type: "none", source: "none" });
const res = await request(app).get("/api/cli-auth/challenges/12345678-1234-4123-8123-123456789abc?token=pcp_cli_auth_secret");
expect(res.status).toBe(200);
expect(res.body.requiresSignIn).toBe(true);
expect(res.body.canApprove).toBe(false);
});
it.each([
["cloud_tenant", "board", false, false, true],
["cloud_tenant", "instance_admin_required", false, false, false],
["session", "board", false, false, true],
["board_api_key", "board", false, true, false],
])("reports CLI approval for %s requesting %s", async (source, requestedAccess, isInstanceAdmin, requiresSignIn, canApprove) => {
mockBoardAuthService.describeCliAuthChallenge.mockResolvedValue({
id: "12345678-1234-4123-8123-123456789abc", status: "pending", requestedAccess,
});
const app = await createApp({ type: "board", source, userId: "user-1", isInstanceAdmin });
const res = await request(app).get("/api/cli-auth/challenges/12345678-1234-4123-8123-123456789abc?token=pcp_cli_auth_secret");
expect(res.status).toBe(200);
expect(res.body).toMatchObject({ requiresSignIn, canApprove });
});
it.each(["PASTE_ID_HERE", "not-a-uuid"])("rejects malformed challenge ID %s before calling the service", async (id) => {
const app = await createApp({ type: "board", userId: "user-1", source: "session" });
const responses = [
await request(app).get(`/api/cli-auth/challenges/${id}?token=pcp_cli_auth_secret`),
await request(app).post(`/api/cli-auth/challenges/${id}/approve`).send({ token: "pcp_cli_auth_secret" }),
await request(app).post(`/api/cli-auth/challenges/${id}/cancel`).send({ token: "pcp_cli_auth_secret" }),
];
for (const response of responses) {
expect(response.status).toBe(400);
expect(response.body.error).toBe("Invalid CLI auth challenge ID");
}
expect(mockBoardAuthService.describeCliAuthChallenge).not.toHaveBeenCalled();
expect(mockBoardAuthService.approveCliAuthChallenge).not.toHaveBeenCalled();
expect(mockBoardAuthService.cancelCliAuthChallenge).not.toHaveBeenCalled();
expect(mockLogActivity).not.toHaveBeenCalled();
});
it("requires authentication before approving even a malformed challenge ID", async () => {
const app = await createApp({ type: "none", source: "none" });
const res = await request(app)
.post("/api/cli-auth/challenges/PASTE_ID_HERE/approve")
.send({ token: "pcp_cli_auth_secret" });
expect(res.status).toBe(401);
expect(mockBoardAuthService.approveCliAuthChallenge).not.toHaveBeenCalled();
});
it("preserves missing-secret and unknown-challenge responses", async () => {
const app = await createApp({ type: "none", source: "none" });
const path = "/api/cli-auth/challenges/12345678-1234-4123-8123-123456789abc";
const missing = await request(app).get(path);
expect(missing.status).toBe(404);
expect(mockBoardAuthService.describeCliAuthChallenge).not.toHaveBeenCalled();
mockBoardAuthService.describeCliAuthChallenge.mockResolvedValue(null);
const unknown = await request(app).get(`${path}?token=wrong-secret`);
expect(unknown.status).toBe(404);
});
it("cancels a valid challenge and preserves path whitespace normalization", async () => {
mockBoardAuthService.cancelCliAuthChallenge.mockResolvedValue({ status: "cancelled" });
const app = await createApp({ type: "none", source: "none" });
const id = "12345678-1234-4123-8123-123456789ABC";
const res = await request(app)
.post(`/api/cli-auth/challenges/${encodeURIComponent(` ${id} `)}/cancel`)
.send({ token: "pcp_cli_auth_secret" });
expect(res.status).toBe(200);
expect(res.body).toEqual({ status: "cancelled", cancelled: true });
expect(mockBoardAuthService.cancelCliAuthChallenge).toHaveBeenCalledWith(id, "pcp_cli_auth_secret");
});
it("approves a CLI auth challenge for a signed-in board user", async () => {
mockBoardAuthService.approveCliAuthChallenge.mockResolvedValue({
status: "approved",
challenge: {
id: "12345678-1234-4123-8123-123456789abc",
boardApiKeyId: "board-key-1",
requestedAccess: "board",
requestedCompanyId: "company-1",
expiresAt: new Date("2026-03-23T13:00:00.000Z"),
},
});
mockBoardAuthService.resolveBoardAccess.mockResolvedValue({
user: { id: "user-1", name: "User One", email: "user@example.com" },
companyIds: ["company-1"],
isInstanceAdmin: false,
});
mockBoardAuthService.resolveBoardActivityCompanyIds.mockResolvedValue(["company-1"]);
const app = await createApp({
type: "board",
userId: "user-1",
source: "session",
isInstanceAdmin: false,
companyIds: ["company-1"],
});
const res = await request(app)
.post("/api/cli-auth/challenges/12345678-1234-4123-8123-123456789abc/approve")
.send({ token: "pcp_cli_auth_secret" });
expect(res.status).toBe(200);
expect(mockBoardAuthService.approveCliAuthChallenge).toHaveBeenCalledWith(
"12345678-1234-4123-8123-123456789abc",
"pcp_cli_auth_secret",
"user-1",
);
expect(mockBoardAuthService.resolveBoardActivityCompanyIds).not.toHaveBeenCalled();
expect(mockLogActivity).not.toHaveBeenCalled();
});
it("delegates instance-admin approval and atomic auditing to the service", async () => {
mockBoardAuthService.approveCliAuthChallenge.mockResolvedValue({
status: "approved",
challenge: {
id: "12345678-1234-4123-8123-123456789def",
boardApiKeyId: "board-key-2",
requestedAccess: "instance_admin_required",
requestedCompanyId: null,
expiresAt: new Date("2026-03-23T13:00:00.000Z"),
},
});
mockBoardAuthService.resolveBoardActivityCompanyIds.mockResolvedValue(["company-a", "company-b"]);
const app = await createApp({
type: "board",
userId: "admin-1",
source: "session",
isInstanceAdmin: true,
companyIds: [],
});
const res = await request(app)
.post("/api/cli-auth/challenges/12345678-1234-4123-8123-123456789def/approve")
.send({ token: "pcp_cli_auth_secret" });
expect(res.status).toBe(200);
expect(mockBoardAuthService.approveCliAuthChallenge).toHaveBeenCalledWith(
"12345678-1234-4123-8123-123456789def", "pcp_cli_auth_secret", "admin-1",
);
expect(mockBoardAuthService.resolveBoardActivityCompanyIds).not.toHaveBeenCalled();
expect(mockLogActivity).not.toHaveBeenCalled();
});
it("delegates owner-bound revocation and atomic audit to the service", async () => {
mockBoardAuthService.assertCurrentBoardKey.mockResolvedValue({
id: "board-key-3",
userId: "admin-2",
});
mockBoardAuthService.resolveBoardActivityCompanyIds.mockResolvedValue(["company-z"]);
const app = await createApp({
type: "board",
userId: "admin-2",
keyId: "board-key-3",
source: "board_key",
isInstanceAdmin: true,
companyIds: [],
});
const res = await request(app).post("/api/cli-auth/revoke-current").send({});
expect(res.status).toBe(200);
expect(mockBoardAuthService.revokeBoardApiKey).toHaveBeenCalledWith("board-key-3", {
userId: "admin-2", revokedVia: "cli_auth_logout",
});
expect(mockBoardAuthService.resolveBoardActivityCompanyIds).not.toHaveBeenCalled();
expect(mockLogActivity).not.toHaveBeenCalled();
});
it("creates a named board API key and logs audit activity", async () => {
mockBoardAuthService.createNamedBoardApiKey.mockResolvedValue({
id: "board-key-4",
name: "external-admin",
token: "pcp_board_plaintext",
createdAt: new Date("2026-05-23T12:00:00.000Z"),
lastUsedAt: null,
revokedAt: null,
expiresAt: new Date("2026-06-23T12:00:00.000Z"),
});
mockBoardAuthService.resolveBoardActivityCompanyIds.mockResolvedValue(["11111111-1111-4111-8111-111111111111"]);
const app = await createApp({
type: "board",
userId: "user-1",
source: "board_key",
isInstanceAdmin: false,
companyIds: ["11111111-1111-4111-8111-111111111111"],
});
const res = await request(app)
.post("/api/board-api-keys")
.send({
name: "external-admin",
requestedCompanyId: "11111111-1111-4111-8111-111111111111",
expiresAt: "2026-06-23T12:00:00.000Z",
});
expect(res.status, res.text || JSON.stringify(res.body)).toBe(201);
expect(res.body).toMatchObject({
id: "board-key-4",
name: "external-admin",
token: "pcp_board_plaintext",
expiresAt: "2026-06-23T12:00:00.000Z",
});
expect(mockBoardAuthService.createNamedBoardApiKey).toHaveBeenCalledWith({
userId: "user-1",
name: "external-admin",
expiresAt: new Date("2026-06-23T12:00:00.000Z"),
});
expect(mockLogActivity).toHaveBeenCalledWith(
expect.anything(),
expect.objectContaining({
companyId: "11111111-1111-4111-8111-111111111111",
action: "board_api_key.created",
details: expect.objectContaining({ name: "external-admin" }),
}),
);
});
it("lists and revokes named board API keys for the current board user", async () => {
const keyId = "55555555-5555-4555-8555-555555555555";
mockBoardAuthService.listBoardApiKeys.mockResolvedValue([
{
id: keyId,
name: "external-admin",
createdAt: new Date("2026-05-23T12:00:00.000Z"),
lastUsedAt: null,
revokedAt: null,
expiresAt: null,
},
]);
mockBoardAuthService.getBoardApiKeyForUser.mockResolvedValue({
id: keyId,
userId: "user-1",
name: "external-admin",
});
mockBoardAuthService.revokeBoardApiKey.mockResolvedValue({
id: keyId,
userId: "user-1",
name: "external-admin",
});
mockBoardAuthService.resolveBoardActivityCompanyIds.mockResolvedValue(["company-1"]);
const app = await createApp({
type: "board",
userId: "user-1",
source: "board_key",
isInstanceAdmin: false,
companyIds: ["company-1"],
});
const listRes = await request(app).get("/api/board-api-keys");
expect(listRes.status).toBe(200);
expect(listRes.body[0]).toMatchObject({ id: keyId, name: "external-admin" });
expect(mockBoardAuthService.listBoardApiKeys).toHaveBeenCalledWith(
"user-1",
{ includeInactive: false },
);
const revokeRes = await request(app).delete(`/api/board-api-keys/${keyId}`);
expect(revokeRes.status).toBe(200);
expect(revokeRes.body).toEqual({ ok: true, keyId });
expect(mockBoardAuthService.revokeBoardApiKey).toHaveBeenCalledWith(keyId, {
userId: "user-1", revokedVia: "board_api_key_lifecycle",
});
expect(mockBoardAuthService.resolveBoardActivityCompanyIds).not.toHaveBeenCalled();
expect(mockLogActivity).not.toHaveBeenCalled();
});
it("rejects malformed board API key IDs before database lookup", async () => {
const app = await createApp({
type: "board",
userId: "user-1",
source: "board_key",
isInstanceAdmin: false,
companyIds: ["company-1"],
});
const res = await request(app).delete("/api/board-api-keys/not-a-uuid");
expect(res.status).toBe(400);
expect(mockBoardAuthService.getBoardApiKeyForUser).not.toHaveBeenCalled();
expect(mockBoardAuthService.revokeBoardApiKey).not.toHaveBeenCalled();
});
});