evOo-local/packages/adapters/src/run-secret.test.ts
cynarAI 6c7eed7580 Initial clean evOo-local from f00577b
Fresh history cut from cynarAI/evoo antigravity-handoff/project-timeline
(Voice First + project timeline). Brand docs/titles as evOo; keep @rakazo/*
packages as tech debt. Excludes node_modules, caches, secrets, voice blobs.
2026-09-20 17:15:16 +02:00

283 lines
8.2 KiB
TypeScript

import { describe, expect, it, vi } from "vitest";
import {
commitConsumedRunSecret,
normalizeSecretAskPurpose,
reconcileManagedConnection,
resolveCompletedSecretLeftover,
resolveMissingRunSecretAction,
runSecretKind,
secretPausedToolResult,
tryCompleteConnectionWithCode,
} from "./run-secret.js";
describe("runSecretKind", () => {
it("scopes secrets to a single run", () => {
expect(runSecretKind("run-1")).toBe("run-secret:run-1");
});
});
describe("normalizeSecretAskPurpose", () => {
it("keeps known purposes and defaults unknown ones to otp", () => {
expect(normalizeSecretAskPurpose("api_key")).toBe("api_key");
expect(normalizeSecretAskPurpose("password")).toBe("password");
expect(normalizeSecretAskPurpose("other")).toBe("otp");
expect(normalizeSecretAskPurpose("otp")).toBe("otp");
expect(normalizeSecretAskPurpose(undefined)).toBe("otp");
});
});
describe("secretPausedToolResult", () => {
it("terminates the agent turn without exposing a value", () => {
expect(secretPausedToolResult()).toMatchObject({
terminate: true,
details: { secret: "paused" },
});
});
});
describe("commitConsumedRunSecret", () => {
it("deletes the stored secret before connector side effects, then persists", async () => {
const order: string[] = [];
const result = { ok: true, submitted: true };
const onPersistFailed = { error: "uncertain", uncertain: true as const };
await expect(
commitConsumedRunSecret({
deleteSecret: async () => {
order.push("delete");
},
afterSecretTaken: async () => {
order.push("side-effect");
return result;
},
persist: async () => {
order.push("persist");
return true;
},
onPersistFailed,
}),
).resolves.toBe(result);
expect(order).toEqual(["delete", "side-effect", "persist"]);
});
it("does not keep the secret for a retry after side effects when persist fails", async () => {
const deleteSecret = vi.fn();
const onPersistFailed = { error: "uncertain", uncertain: true as const };
await expect(
commitConsumedRunSecret({
deleteSecret,
afterSecretTaken: async () => ({ ok: true, submitted: true }),
persist: async () => false,
onPersistFailed,
}),
).resolves.toBe(onPersistFailed);
expect(deleteSecret).toHaveBeenCalledOnce();
});
});
describe("resolveCompletedSecretLeftover", () => {
it("drops a leftover OTP created before the effect completed", () => {
expect(
resolveCompletedSecretLeftover({
secretCreatedAt: new Date("2026-08-27T12:00:00.000Z"),
effectUpdatedAt: new Date("2026-08-27T12:00:05.000Z"),
}),
).toBe("drop_leftover");
});
it("consumes a replacement OTP submitted after the effect completed", () => {
expect(
resolveCompletedSecretLeftover({
secretCreatedAt: new Date("2026-08-27T12:01:00.000Z"),
effectUpdatedAt: new Date("2026-08-27T12:00:05.000Z"),
}),
).toBe("consume_replacement");
});
});
describe("resolveMissingRunSecretAction", () => {
it("replays a completed effect instead of asking again after the secret was deleted", () => {
const result = { ok: true, submitted: true, connected: true };
expect(resolveMissingRunSecretAction({ status: "completed", result })).toEqual({
action: "return",
result,
});
});
it("settles an in-flight attempt instead of re-asking for a consumed OTP", () => {
expect(resolveMissingRunSecretAction({ status: "executing" })).toEqual({
action: "settle_attempt",
});
});
it("asks again when the effect is still waiting for input", () => {
expect(resolveMissingRunSecretAction({ status: "intended" })).toEqual({ action: "ask" });
expect(resolveMissingRunSecretAction(undefined)).toEqual({ action: "ask" });
});
});
describe("reconcileManagedConnection", () => {
const context = {
operationId: "run-1",
traceId: "run-1",
spaceId: "workspace-1",
userId: "user-1",
signal: new AbortController().signal,
};
it("marks a pending connection connected when the provider is already ready", async () => {
const connectionReady = vi.fn().mockResolvedValue(true);
const prisma = {
connection: {
findFirst: vi.fn().mockResolvedValue({
id: "conn-1",
connectorId: "composio",
provider: "gmail",
status: "pending",
}),
update: vi.fn().mockResolvedValue({}),
},
};
const connectors = {
managed: vi.fn(() => ({ connectionReady })),
};
await expect(
reconcileManagedConnection(
prisma as never,
connectors as never,
{ spaceId: "workspace-1", userId: "user-1" },
context,
"conn-1",
),
).resolves.toBe("connected");
expect(connectionReady).toHaveBeenCalled();
expect(prisma.connection.update).toHaveBeenCalledWith({
where: { id: "conn-1" },
data: { status: "connected" },
});
});
});
describe("tryCompleteConnectionWithCode", () => {
const context = {
operationId: "run-1",
traceId: "run-1",
spaceId: "workspace-1",
userId: "user-1",
signal: new AbortController().signal,
};
it("forwards the code to a pending managed connector", async () => {
const complete = vi.fn().mockResolvedValue({ connectionRef: "gmail" });
const connectionReady = vi.fn().mockResolvedValue(true);
const prisma = {
connection: {
findFirst: vi.fn().mockResolvedValue({
id: "conn-1",
connectorId: "composio",
provider: "gmail",
providerRef: "gmail-state",
status: "pending",
}),
update: vi.fn().mockResolvedValue({}),
},
};
const connectors = {
managed: vi.fn(() => ({ complete, connectionReady })),
};
await expect(
tryCompleteConnectionWithCode(
prisma as never,
connectors as never,
{ spaceId: "workspace-1", userId: "user-1" },
context,
"conn-1",
"123456",
),
).resolves.toEqual({ connected: true });
expect(prisma.connection.findFirst).toHaveBeenCalledWith({
where: {
id: "conn-1",
spaceId: "workspace-1",
userId: "user-1",
status: { in: ["pending", "connected"] },
},
});
expect(complete).toHaveBeenCalledWith({ state: "gmail-state", code: "123456" }, context);
expect(prisma.connection.update).toHaveBeenCalledWith({
where: { id: "conn-1" },
data: { status: "connected" },
});
});
it("does not resubmit a code when the connection is already connected", async () => {
const complete = vi.fn();
const prisma = {
connection: {
findFirst: vi.fn().mockResolvedValue({
id: "conn-1",
connectorId: "composio",
provider: "gmail",
providerRef: "gmail-state",
status: "connected",
}),
update: vi.fn(),
},
};
const connectors = {
managed: vi.fn(() => ({ complete, connectionReady: vi.fn() })),
};
await expect(
tryCompleteConnectionWithCode(
prisma as never,
connectors as never,
{ spaceId: "workspace-1", userId: "user-1" },
context,
"conn-1",
"123456",
),
).resolves.toEqual({ connected: true });
expect(complete).not.toHaveBeenCalled();
expect(prisma.connection.update).not.toHaveBeenCalled();
});
it("returns a connector error instead of throwing", async () => {
const complete = vi.fn().mockRejectedValue(new Error("invalid code"));
const prisma = {
connection: {
findFirst: vi.fn().mockResolvedValue({
id: "conn-1",
connectorId: "composio",
provider: "gmail",
providerRef: "gmail-state",
status: "pending",
}),
update: vi.fn(),
},
};
const connectors = {
managed: vi.fn(() => ({ complete, connectionReady: vi.fn() })),
};
await expect(
tryCompleteConnectionWithCode(
prisma as never,
connectors as never,
{ spaceId: "workspace-1", userId: "user-1" },
context,
"conn-1",
"bad",
),
).resolves.toEqual({ connected: false, error: "Connection could not be completed." });
});
});