1415 lines · 62.1 KB · TypeScript
RawDownload
// ---------------------------------------------------------------------------// The cloud membership mirror: `WorkOsMirror` (writes) + the cloud// `MemberDirectory` (reads), against the real PGlite Postgres every cloud// unit test runs on (scripts/test-globalsetup.ts), through the same// `DbService.Live` the request path uses.//// What this pins://   - an older WorkOS payload never overwrites a newer row (replay-safe)//   - a delete tombstones the row (inactive, `deleted_at` set) by IDENTITY://     no payload naming the deleted membership id ever reactivates it,//     however it is stamped — not a stale one, not one stamped after the//     removal — while a replacement under a NEW id takes the row over live;//     every default read treats the tombstone as no membership//   - a membership WorkOS merely deactivated (inactive, no `deleted_at`)//     reactivates under the same id like any other update//   - a delete of a membership or user the mirror has not seen yet leaves//     the tombstone behind, so the backfill's older payload cannot insert//     the row live afterwards//   - a delete of a membership id the row does NOT hold (the member's row//     still carries the id it was replaced from) is recorded all the same,//     so a later, newer payload of the deleted id cannot take the row over//   - a deleted user takes no membership at all, however the payload is//     stamped: the account tombstone refuses the insert by identity — and a//     membership write racing the deletion waits for its commit and sees//     the tombstone, never inserting a live membership for a deleted user//   - a delete with no WorkOS instant keeps the row's own WorkOS stamp, so//     a replacement membership WorkOS created meanwhile is not refused,//     while the removed membership's own payload still is//   - the cursor advances only by compare-and-set (one owner per stream),//     and a page that loses the CAS writes nothing//   - a backfill scan is applied only if its listing is newer than the one//     already applied to the organization (one owner per listing instant),//     so an older listing cannot insert a membership the newer one lacked;//     a deleted organization takes no scan//   - a membership payload stamped before the organization's last scan is//     refused (a login list fetched before a revocation the scan already//     applied cannot reinstate it); one stamped at or after it is written —//     and a write racing a scan waits for the scan's commit and sees its//     mark, so it cannot insert a membership the scan just proved revoked//   - the events replay boundary is recorded once and never advanced//   - `members` searches email AND name case-insensitively, pages stably//   - `findByEmail` ignores the casing WorkOS stored//   - `membershipById` is org-scoped: another org's id resolves to null//   - a membership arriving before its user still holds (FK via ensureAccount)// --------------------------------------------------------------------------- import { describe, expect, it } from "@effect/vitest";import { eq, sql } from "drizzle-orm";import { Context, Deferred, Duration, Effect, Fiber, Layer, Option } from "effect"; import { MemberDirectory } from "@executor-js/api/server"; import { DbService, makeDbLayer } from "../db/db";import { accounts, organizations } from "../db/schema";import { cloudMemberDirectoryLayer } from "./member-directory";import { UserStoreService } from "./context";import {  WorkOsMirror,  WorkOsMirrorWrite,  type WorkOsMirrorMembership,  type WorkOsMirrorUser,} from "./workos-mirror";import { makeWorkOsMirrorStore } from "./workos-mirror-store";import {  MIRROR_RECONCILER_LAG_BUDGET,  MirrorReadinessState,  mirrorReadinessFrom,  readMirrorReadiness,} from "./mirror-readiness-store"; const DbLive = DbService.Live;const Services = Layer.mergeAll(  WorkOsMirror.Live,  cloudMemberDirectoryLayer,  UserStoreService.Live,).pipe(Layer.provideMerge(DbLive)); const run = <A, E>(  body: Effect.Effect<A, E, WorkOsMirror | MemberDirectory | UserStoreService | DbService>,) => Effect.runPromise(body.pipe(Effect.provide(Services), Effect.scoped)); /** The events row is instance-wide: drop it so a test starts as a never-backfilled database. */const clearEventsRow = Effect.flatMap(DbService.asEffect(), ({ db }) =>  Effect.promise(() => db.execute(sql`delete from workos_sync where id = 'events'`)),); const at = (iso: string) => new Date(iso);const T1 = at("2026-01-01T00:00:00.000Z");const T2 = at("2026-01-02T00:00:00.000Z");const T3 = at("2026-01-03T00:00:00.000Z");const T4 = at("2026-01-04T00:00:00.000Z"); // Every test mints its own org so the shared test database never couples// them; ids are synthetic placeholders, never real identities.const freshOrg = () =>  Effect.gen(function* () {    const id = `org_${crypto.randomUUID().replaceAll("-", "")}`;    const store = yield* UserStoreService;    yield* store.use("upsertOrganization", (s) =>      s.upsertOrganization({ id, name: "Mirror Org", updatedAt: T1 }),    );    return id;  }); const user = (id: string, overrides: Partial<WorkOsMirrorUser> = {}): WorkOsMirrorUser => ({  id,  email: `${id}@placeholder.test`,  firstName: null,  lastName: null,  avatarUrl: null,  lastSignInAt: null,  updatedAt: T1,  ...overrides,}); const membership = (  organizationId: string,  accountId: string,  overrides: Partial<WorkOsMirrorMembership> = {},): WorkOsMirrorMembership => ({  id: `om_${accountId}_${organizationId}`,  accountId,  organizationId,  role: "member",  status: "active",  updatedAt: T1,  ...overrides,}); describe("WorkOsMirror upserts", () => {  it("ignores a user payload older than the stored row, accepts a newer one", async () => {    const result = await run(      Effect.gen(function* () {        const mirror = yield* WorkOsMirror;        const directory = yield* MemberDirectory;        const org = yield* freshOrg();        const id = `user_${crypto.randomUUID()}`;        yield* mirror.upsertMembership(membership(org, id));         const first = yield* mirror.upsertUser(user(id, { firstName: "Ada", updatedAt: T2 }));        const stale = yield* mirror.upsertUser(user(id, { firstName: "Stale", updatedAt: T1 }));        const afterStale = yield* directory.membership(id, org);        const newer = yield* mirror.upsertUser(user(id, { firstName: "Newer", updatedAt: T3 }));        const afterNewer = yield* directory.membership(id, org);        return { first, stale, newer, afterStale, afterNewer };      }),    );    expect(result.first).toBe(true);    expect(result.stale, "an older payload is reported as not written").toBe(false);    expect(result.afterStale?.name, "and left the newer row untouched").toBe("Ada");    expect(result.newer).toBe(true);    expect(result.afterNewer?.name).toBe("Newer");  });   it("ignores a membership payload older than the stored row", async () => {    const result = await run(      Effect.gen(function* () {        const mirror = yield* WorkOsMirror;        const directory = yield* MemberDirectory;        const org = yield* freshOrg();        const id = `user_${crypto.randomUUID()}`;        yield* mirror.upsertUser(user(id));        yield* mirror.upsertMembership(membership(org, id, { role: "admin", updatedAt: T2 }));        const stale = yield* mirror.upsertMembership(          membership(org, id, {            role: "member",            status: "inactive",            updatedAt: T1,          }),        );        const row = yield* directory.membership(id, org);        const equal = yield* mirror.upsertMembership(          membership(org, id, { role: "member", updatedAt: T2 }),        );        const afterEqual = yield* directory.membership(id, org);        return { stale, row, equal, afterEqual };      }),    );    expect(result.stale).toBe(false);    expect(result.row?.role).toBe("admin");    expect(result.row?.status).toBe("active");    // Equal timestamps are accepted: the feeders replay the same payload and    // must converge, not stall.    expect(result.equal).toBe(true);    expect(result.afterEqual?.role).toBe("member");  });   it("mints the account row when a membership arrives before its user", async () => {    const result = await run(      Effect.gen(function* () {        const mirror = yield* WorkOsMirror;        const directory = yield* MemberDirectory;        const org = yield* freshOrg();        const id = `user_${crypto.randomUUID()}`;        const written = yield* mirror.upsertMembership(membership(org, id));        const bare = yield* directory.membership(id, org);        // The bare row has no timestamp, so the first user payload — even an        // "old" one — fills it.        yield* mirror.upsertUser(user(id, { firstName: "Late", updatedAt: T1 }));        const filled = yield* directory.membership(id, org);        return { written, bare, filled };      }),    );    expect(result.written).toBe(true);    expect(result.bare).not.toBeNull();    expect(result.bare?.email).toBeNull();    expect(result.filled?.name).toBe("Late");  });   it("tombstones a deleted membership by identity: no payload of that id resurrects it, a replacement under a new id does", async () => {    const result = await run(      Effect.gen(function* () {        const mirror = yield* WorkOsMirror;        const directory = yield* MemberDirectory;        const org = yield* freshOrg();        const id = `user_${crypto.randomUUID()}`;        const membershipId = `om_${id}_${org}`;        yield* mirror.upsertUser(user(id));        yield* mirror.upsertMembership(membership(org, id, { id: membershipId, updatedAt: T1 }));         const ref = { id: membershipId, accountId: id, organizationId: org };        const removed = yield* mirror.deleteMembership(ref, T2);        const removedAgain = yield* mirror.deleteMembership(ref, T2);        const byDefault = yield* directory.membership(id, org);        const listed = yield* directory.members(org);        const asInactive = yield* directory.membership(id, org, ["inactive"]);         // A feeder that fetched the membership BEFORE the deletion (login,        // backfill) writes it after: the guard refuses it.        const stale = yield* mirror.upsertMembership(          membership(org, id, { id: membershipId, updatedAt: T1 }),        );        const afterStale = yield* directory.membership(id, org, ["inactive"]);        // An active payload stamped the SAME instant as the deletion: the        // tombstone wins, a deletion at T is never undone by a payload at T.        const equal = yield* mirror.upsertMembership(          membership(org, id, { id: membershipId, updatedAt: T2 }),        );        const afterEqual = yield* directory.membership(id, org, ["inactive"]);        // A role change issued before the removal and delivered after it (a        // stalled login list, a lagging feeder), stamped NEWER than anything        // the row holds — the payload a timestamp guard would let through.        // Same id: the membership is deleted, it never returns.        const newerSameId = yield* mirror.upsertMembership(          membership(org, id, {            id: membershipId,            role: "admin",            updatedAt: T3,          }),        );        const afterNewerSameId = yield* directory.membership(id, org, ["inactive"]);        // The member re-added in WorkOS: a payload newer than the deletion,        // under a new membership id (a deleted id is never reused).        const readded = yield* mirror.upsertMembership(          membership(org, id, { id: `${membershipId}_2`, updatedAt: T3 }),        );        const afterReadd = yield* directory.membership(id, org);        // The OLD membership's deletion, replayed after the re-add: the        // newer row, under its new id, stands.        const lateDelete = yield* mirror.deleteMembership(ref, T2);        const afterLateDelete = yield* directory.membership(id, org);        // The same deletion stamped AFTER the replacement (a removal Executor        // made whose clock was read once WorkOS had answered, by which time        // the member had been re-added): the row is another membership, so        // the timestamp does not make it deletable.        const lateDeleteNewerStamp = yield* mirror.deleteMembership(ref, T4);        const afterLateDeleteNewerStamp = yield* directory.membership(id, org);        return {          removed,          removedAgain,          byDefault,          listed,          asInactive,          stale,          afterStale,          equal,          afterEqual,          newerSameId,          afterNewerSameId,          readded,          afterReadd,          lateDelete,          afterLateDelete,          lateDeleteNewerStamp,          afterLateDeleteNewerStamp,        };      }),    );    expect(result.removed).toBe(true);    expect(result.removedAgain, "a replayed delete changes nothing").toBe(false);    expect(result.byDefault, "a tombstone reads as no membership").toBeNull();    expect(result.listed, "and is not listed").toEqual([]);    expect(result.asInactive, "but is still there when asked for").toMatchObject({      status: "inactive",      lastActiveAt: null,    });    expect(result.stale, "an upsert older than the deletion is refused").toBe(false);    expect(result.afterStale?.status).toBe("inactive");    expect(result.equal, "an upsert stamped AT the deletion is refused too").toBe(false);    expect(result.afterEqual?.status).toBe("inactive");    expect(      result.newerSameId,      "a payload of the deleted id stamped AFTER the removal is refused: identity, not time",    ).toBe(false);    expect(result.afterNewerSameId).toMatchObject({      status: "inactive",      role: "member",    });    expect(result.readded, "a replacement under a new id reactivates").toBe(true);    expect(result.afterReadd?.status).toBe("active");    expect(result.lateDelete, "a replayed deletion of the OLD id is refused").toBe(false);    expect(result.afterLateDelete?.status).toBe("active");    expect(      result.lateDeleteNewerStamp,      "a deletion of the OLD id stamped after the replacement is refused too: identity, not time",    ).toBe(false);    expect(result.afterLateDeleteNewerStamp).toMatchObject({      status: "active",      membershipId: `om_${result.afterLateDeleteNewerStamp?.accountId}_${result.afterLateDeleteNewerStamp?.organizationId}_2`,    });  });   it("keeps the row's own WorkOS stamp on a delete with no instant, so a replacement created meanwhile is accepted and the removed payload is not", async () => {    const result = await run(      Effect.gen(function* () {        const mirror = yield* WorkOsMirror;        const directory = yield* MemberDirectory;        const org = yield* freshOrg();        const id = `user_${crypto.randomUUID()}`;        const membershipId = `om_${id}_${org}`;        const ref = { id: membershipId, accountId: id, organizationId: org };        yield* mirror.upsertUser(user(id));        yield* mirror.upsertMembership(membership(org, id, { id: membershipId, updatedAt: T1 }));         // Executor removes the member holding no WorkOS instant for it, so        // the tombstone keeps T1, the last state WorkOS reported for it —        // never the local clock, which is long past T2 here.        const removed = yield* mirror.deleteMembership(ref, null);        const removedAgain = yield* mirror.deleteMembership(ref, null);        const tombstone = yield* directory.membership(id, org, ["inactive"]);        // A login that fetched the membership before the removal: refused.        const stale = yield* mirror.upsertMembership(          membership(org, id, { id: membershipId, updatedAt: T1 }),        );        // The member re-added in WorkOS while the removal was in flight,        // under a new id and stamped before any local clock could have        // stamped the tombstone: accepted.        const replaced = yield* mirror.upsertMembership(          membership(org, id, { id: `${membershipId}_2`, updatedAt: T2 }),        );        const afterReplace = yield* directory.membership(id, org);        // A tombstone minted for a row the mirror never held has no stamp        // to keep; it is still a tombstone.        const other = `user_${crypto.randomUUID()}`;        const minted = yield* mirror.deleteMembership(          { id: `om_${other}_${org}`, accountId: other, organizationId: org },          null,        );        const mintedRow = yield* directory.membership(other, org, ["inactive"]);        return {          membershipId,          removed,          removedAgain,          tombstone,          stale,          replaced,          afterReplace,          minted,          mintedRow,        };      }),    );    expect(result.removed).toBe(true);    expect(result.removedAgain, "a repeated removal changes nothing").toBe(false);    expect(result.tombstone?.status).toBe("inactive");    expect(result.stale, "the pre-removal payload is refused").toBe(false);    expect(result.replaced, "a replacement newer than the row's stamp is accepted").toBe(true);    expect(result.afterReplace).toMatchObject({      status: "active",      membershipId: `${result.membershipId}_2`,    });    expect(result.minted, "a row the mirror never held is still tombstoned").toBe(true);    expect(result.mintedRow?.status).toBe("inactive");  });   it("tombstones a membership the mirror has not seen, so a later older payload cannot insert it live", async () => {    const result = await run(      Effect.gen(function* () {        const mirror = yield* WorkOsMirror;        const directory = yield* MemberDirectory;        const org = yield* freshOrg();        const id = `user_${crypto.randomUUID()}`;        const membershipId = `om_${id}_${org}`;        const readdedId = `${membershipId}_2`;        const ref = { id: membershipId, accountId: id, organizationId: org };         // The reconciler applies the deletion before the backfill has        // inserted the row (the user is unknown too).        const removed = yield* mirror.deleteMembership(ref, T2);        const removedAgain = yield* mirror.deleteMembership(ref, T2);        const tombstone = yield* directory.membership(id, org, ["inactive"]);        // The backfill, listing WorkOS as it was before the deletion, now        // writes the membership: refused, the tombstone stands.        const backfilled = yield* mirror.upsertMembership(          membership(org, id, { id: membershipId, updatedAt: T1 }),        );        const afterBackfill = yield* directory.membership(id, org);        // The user payload still fills the bare account row the tombstone        // minted, so the inactive row reads with its profile.        yield* mirror.upsertUser(user(id, { firstName: "Late", updatedAt: T1 }));        const profiled = yield* directory.membership(id, org, ["inactive"]);        // Re-added in WorkOS later under a NEW membership id.        const readded = yield* mirror.upsertMembership(          membership(org, id, { id: readdedId, updatedAt: T3 }),        );        const afterReadd = yield* directory.membership(id, org);        return {          readdedId,          removed,          removedAgain,          tombstone,          backfilled,          afterBackfill,          profiled,          readded,          afterReadd,        };      }),    );    expect(result.removed, "the delete leaves a tombstone behind").toBe(true);    expect(result.removedAgain).toBe(false);    expect(result.tombstone).toMatchObject({ status: "inactive", email: null });    expect(result.backfilled, "the pre-deletion payload is refused").toBe(false);    expect(result.afterBackfill, "and the member is not live").toBeNull();    expect(result.profiled?.name).toBe("Late");    expect(result.readded).toBe(true);    expect(result.afterReadd).toMatchObject({      status: "active",      membershipId: result.readdedId,    });  });   it("records a delete whose id the row does not hold, so a newer payload of that id cannot take the row over", async () => {    const result = await run(      Effect.gen(function* () {        const mirror = yield* WorkOsMirror;        const directory = yield* MemberDirectory;        const org = yield* freshOrg();        const id = `user_${crypto.randomUUID()}`;        const membershipA = `om_${id}_${org}_a`;        const membershipB = `om_${id}_${org}_b`;        yield* mirror.upsertUser(user(id));        // The mirror holds A (a stale listing). In WorkOS, A was already        // replaced by B (stamped T2), and B is then deleted (T3) before any        // feeder wrote B here.        yield* mirror.upsertMembership(membership(org, id, { id: membershipA, updatedAt: T1 }));        const refB = { id: membershipB, accountId: id, organizationId: org };        const deletedB = yield* mirror.deleteMembership(refB, T3);        const deletedBAgain = yield* mirror.deleteMembership(refB, T3);        const rowAfterDelete = yield* directory.membership(id, org);        // A delayed scan, listed before B's deletion, now writes B: stamped        // after A and under another id, exactly what the row guard lets        // through — the ledger refuses it.        const lateB = yield* mirror.upsertMembership(          membership(org, id, { id: membershipB, updatedAt: T2 }),        );        const afterLateB = yield* directory.membership(id, org);        // A's own deletion, applied later, tombstones the row it holds.        const deletedA = yield* mirror.deleteMembership(          { id: membershipA, accountId: id, organizationId: org },          T3,        );        const afterDeleteA = yield* directory.membership(id, org);        // The member re-added in WorkOS under a third id: accepted.        const readded = yield* mirror.upsertMembership(          membership(org, id, { id: `${membershipB}_c`, updatedAt: T4 }),        );        const afterReadd = yield* directory.membership(id, org);        return {          deletedB,          deletedBAgain,          rowAfterDelete,          lateB,          afterLateB,          deletedA,          afterDeleteA,          readded,          afterReadd,          membershipA,        };      }),    );    expect(result.deletedB, "the delete is recorded even though the row holds another id").toBe(      true,    );    expect(result.deletedBAgain, "a replayed delete records nothing new").toBe(false);    expect(      result.rowAfterDelete?.membershipId,      "the row under A is not B's to tombstone and stands",    ).toBe(result.membershipA);

Lines 1–500 of 1415.