Files
HiveGrid-Wireframes/03 Quellen und Referenzen/hivegrid-cloud/apps/web/app/utils/integrations/appsEngineService.credentials.test.ts
T

76 lines
3.1 KiB
TypeScript

// @vitest-environment node
import { beforeEach, describe, expect, it, vi } from "vitest";
const mocks = vi.hoisted(() => ({
row: null as null | {
id: string;
appId: string;
label: string;
connectionStatus: "active" | "degraded" | "broken" | "revoked" | "pending";
credentialsCiphertext: string | null;
},
decryptTenantField: vi.fn(async () => JSON.stringify({ accessToken: "fixture-token" })),
}));
vi.mock("~/utils/db/.server/tenantRls.server", () => ({
withTenantRLS: async (_tenantId: string, callback: (tx: unknown) => Promise<unknown>) =>
callback({ dataConnection: { findFirst: vi.fn(async () => mocks.row) } }),
}));
vi.mock("@hivegrid/db/crypto/tenant-envelope.server", () => ({
decryptTenantField: mocks.decryptTenantField,
encryptTenantField: vi.fn(),
}));
vi.mock("@hivegrid/db/audit-events.server", () => ({ createAuditEvent: vi.fn() }));
vi.mock("@hivegrid/db/notifications.server", () => ({ createNotificationDelivery: vi.fn() }));
vi.mock("~/utils/db.server", () => ({ db: {} }));
vi.mock("@hivegrid/integrations", () => ({ resolveAdapter: vi.fn() }));
import { AppsEngineServiceError, runWithConnectionCredentials } from "./appsEngineService.server";
describe("runWithConnectionCredentials", () => {
beforeEach(() => {
mocks.decryptTenantField.mockClear();
mocks.row = {
id: "connection-1",
appId: "aircall",
label: "Aircall",
connectionStatus: "active",
credentialsCiphertext: "sealed",
};
});
it("decrypts only after a tenant-scoped app match and passes frozen credentials to the callback", async () => {
const result = await runWithConnectionCredentials(
{ tenantId: "tenant-1", connectionId: "connection-1", expectedAppId: "aircall" },
async (credentials, connection) => ({ credentials, connection }),
);
expect(result.connection).toEqual({ id: "connection-1", appId: "aircall", label: "Aircall" });
expect(result.credentials).toEqual({ accessToken: "fixture-token" });
expect(Object.isFrozen(result.credentials)).toBe(true);
expect(mocks.decryptTenantField).toHaveBeenCalledWith(
"tenant-1",
"sealed",
expect.objectContaining({ client: expect.objectContaining({ dataConnection: expect.any(Object) }) }),
);
});
it("hides a connection belonging to another app", async () => {
await expect(
runWithConnectionCredentials({ tenantId: "tenant-1", connectionId: "connection-1", expectedAppId: "google" }, async () => undefined),
).rejects.toMatchObject({ status: 404 });
expect(mocks.decryptTenantField).not.toHaveBeenCalled();
});
it("rejects revoked or credential-less connections with a Klartext key", async () => {
mocks.row = { ...mocks.row!, connectionStatus: "revoked", credentialsCiphertext: null };
await expect(
runWithConnectionCredentials(
{ tenantId: "tenant-1", connectionId: "connection-1", expectedAppId: "aircall" },
async () => undefined,
),
).rejects.toEqual(
expect.objectContaining<Partial<AppsEngineServiceError>>({ messageKey: "integrations.error.connectionUnavailable" }),
);
});
});