evOo-local/packages/db/src/messaging.postgres.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

195 lines
7.4 KiB
TypeScript

import { afterAll, describe, expect, it } from "vitest";
import { createDb, type PrismaClient } from "./client.js";
import { provisionMessagingIdentity } from "./messaging.js";
const databaseUrl = process.env.DATABASE_URL;
const describePostgres =
process.env.VERIFY_DATABASE && databaseUrl ? describe.sequential : describe.skip;
describePostgres("provisionMessagingIdentity (PostgreSQL)", () => {
const provider = "sendblue";
const address = "+15550001111";
let prisma: PrismaClient;
let close: () => Promise<void>;
let provisioned: { userId: string; spaceId: string; botId: string } | null = null;
afterAll(async () => {
if (provisioned) {
await prisma.messagingIdentity.deleteMany({ where: { provider, address } });
await prisma.organization.deleteMany({ where: { id: provisioned.spaceId } });
await prisma.user.deleteMany({ where: { id: provisioned.userId } });
}
await close?.();
});
it("provisions a user, workspace, bot, thread, and messaging identity row", async () => {
const db = createDb(databaseUrl!);
prisma = db.prisma;
close = async () => {
await db.prisma.$disconnect();
await db.pool.end();
};
const result = await provisionMessagingIdentity(
prisma,
{ provider, address },
{ signupsEnabled: undefined, signupAllowlist: undefined },
);
provisioned = result;
expect(result.created).toBe(true);
expect(result.provider).toBe(provider);
expect(result.address).toBe(address);
const user = await prisma.user.findUnique({
where: { id: result.userId },
include: { accounts: true, members: true },
});
expect(user).toBeTruthy();
expect(user!.email).toMatch(/^msg-[a-f0-9]{32}@messaging\.invalid$/);
expect(user!.accounts).toHaveLength(0);
expect(user!.members).toHaveLength(1);
expect(user!.members[0]!.organizationId).toBe(result.spaceId);
expect(user!.members[0]!.role).toBe("owner");
const org = await prisma.organization.findUnique({ where: { id: result.spaceId } });
expect(org!.name).toBe("Personal");
expect(org!.slug).toBe(`user-${result.userId.slice(0, 12)}`);
const space = await prisma.space.findUnique({
where: { id: result.spaceId },
include: { memberships: true },
});
expect(space).toMatchObject({
organizationId: org!.id,
name: "Personal",
});
expect(space!.memberships).toEqual([expect.objectContaining({ userId: result.userId })]);
const bot = await prisma.bot.findUnique({
where: { id: result.botId },
include: { thread: true },
});
expect(bot).toBeTruthy();
expect(bot!.spaceId).toBe(result.spaceId);
expect(bot!.userId).toBe(result.userId);
expect(bot!.thread).toBeTruthy();
expect(result.threadId).toBe(bot!.thread!.id);
const identity = await prisma.messagingIdentity.findUnique({
where: { provider_address: { provider, address } },
});
expect(identity).toBeTruthy();
expect(identity!.userId).toBe(result.userId);
expect(identity!.spaceId).toBe(result.spaceId);
expect(identity!.botId).toBe(result.botId);
expect(identity!.dmThreadId).toBeNull();
expect(identity!.outboundSinceInbound).toBe(0);
expect(identity!.verifiedAt).toBeNull();
// bootstrap parity: same surrounding rows the auth signup hook creates
const memories = await prisma.memoryDocument.findMany({
where: { spaceId: result.spaceId, userId: result.userId },
});
expect(memories.some((m) => m.scope === "user" && m.path === "MEMORY.md")).toBe(true);
expect(memories.some((m) => m.scope === "bot" && m.botId === result.botId)).toBe(true);
const pref = await prisma.notificationPreference.findFirst({
where: { spaceId: result.spaceId, userId: result.userId },
});
expect(pref).toBeTruthy();
});
it("does not let a texter claim deployment ownership", async () => {
const settings = await prisma.deploymentSettings.findUnique({ where: { id: "default" } });
expect(settings?.ownerUserId ?? null).not.toBe(provisioned!.userId);
});
it("is idempotent for a repeat inbound from the same address", async () => {
const again = await provisionMessagingIdentity(
prisma,
{ provider, address },
{ signupsEnabled: undefined, signupAllowlist: undefined },
);
expect(again.created).toBe(false);
expect(again.userId).toBe(provisioned!.userId);
expect(again.spaceId).toBe(provisioned!.spaceId);
expect(again.botId).toBe(provisioned!.botId);
const users = await prisma.user.findMany({
where: { id: provisioned!.userId },
});
expect(users).toHaveLength(1);
const identities = await prisma.messagingIdentity.findMany({ where: { provider, address } });
expect(identities).toHaveLength(1);
});
it("does not reuse a legacy synthetic email without an identity binding", async () => {
const partialAddress = "+15550002222";
// This could be an abandoned attempt or an attacker registration. An
// email address alone cannot distinguish those origins.
const orphan = await prisma.user.create({
data: {
id: `partial${Date.now()}`,
name: "Sendblue 2222",
email: "msg-sendblue15550002222@messaging.invalid",
emailVerified: false,
},
});
try {
const result = await provisionMessagingIdentity(
prisma,
{ provider, address: partialAddress },
{ signupsEnabled: undefined, signupAllowlist: undefined },
);
expect(result.created).toBe(true);
expect(result.userId).not.toBe(orphan.id);
const identity = await prisma.messagingIdentity.findUnique({
where: { provider_address: { provider, address: partialAddress } },
});
expect(identity).toBeTruthy();
const bots = await prisma.bot.findMany({
where: { spaceId: result.spaceId, userId: result.userId },
});
expect(bots).toHaveLength(1);
await prisma.messagingIdentity.deleteMany({ where: { provider, address: partialAddress } });
await prisma.organization.deleteMany({ where: { id: result.spaceId } });
await prisma.user.deleteMany({ where: { id: result.userId } });
} finally {
await prisma.user.deleteMany({ where: { id: orphan.id } });
}
});
it("resumes after a partial attempt that reached createBot, reusing the orphaned bot", async () => {
const partialAddress = "+15550003333";
// First attempt: let it provision fully, then delete only the identity row.
const first = await provisionMessagingIdentity(
prisma,
{ provider, address: partialAddress },
{ signupsEnabled: undefined, signupAllowlist: undefined },
);
await prisma.messagingIdentity.deleteMany({ where: { provider, address: partialAddress } });
try {
const second = await provisionMessagingIdentity(
prisma,
{ provider, address: partialAddress },
{ signupsEnabled: undefined, signupAllowlist: undefined },
);
expect(second.userId).toBe(first.userId);
expect(second.spaceId).toBe(first.spaceId);
expect(second.botId).toBe(first.botId);
const bots = await prisma.bot.findMany({
where: { spaceId: first.spaceId, userId: first.userId },
});
expect(bots).toHaveLength(1);
} finally {
await prisma.messagingIdentity.deleteMany({ where: { provider, address: partialAddress } });
await prisma.organization.deleteMany({ where: { id: first.spaceId } });
await prisma.user.deleteMany({ where: { id: first.userId } });
}
});
});