import { describe, expect, it } from "@effect/vitest"; import { Effect, Layer } from "effect"; import { AdminUsersForbidden } from "@executor-js/api"; import { MemberDirectory, type DirectoryMember } from "@executor-js/api/server"; import { ApiKeyService } from "../auth/api-keys"; import { UserStoreService } from "../auth/context"; import { ORG_SELECTOR_HEADER } from "../auth/organization"; import { WorkOSClient, type WorkOSClientService } from "../auth/workos"; import { WorkOsMirror, type WorkOsMirrorShape } from "../auth/workos-mirror"; import { authorizeTenant } from "./admin-users-api"; // --------------------------------------------------------------------------- // The admin plane's SESSION credential: an admin member of the selected org, // resolved against the membership mirror through the shared `MemberDirectory`. // The org-key credential is pinned in `auth/org-api-key-auth.node.test.ts`; // this file pins the session branch of `authorizeTenant`: // - an ACTIVE `admin` membership yields the tenant id // - an active plain member is refused // - a pending admin invite is refused (not an admin until accepted) // - no WorkOS call is made past session authentication // --------------------------------------------------------------------------- const ORG = "org_tenant"; const createdAt = new Date("2026-01-01T00:00:00.000Z"); const mirrored = ( accountId: string, overrides: Partial = {}, ): DirectoryMember => ({ accountId, membershipId: `om_${accountId}`, organizationId: ORG, email: null, name: null, avatarUrl: null, role: "member", status: "active", lastActiveAt: null, ...overrides, }); // The mirror as the directory reads it for ORG. const memberships = new Map([ ["user_admin", mirrored("user_admin", { role: "admin" })], ["user_member", mirrored("user_member")], ["user_invited_admin", mirrored("user_invited_admin", { role: "admin", status: "pending" })], ]); const stubDirectory = Layer.succeed(MemberDirectory)({ membership: (accountId, organizationId) => Effect.succeed(organizationId === ORG ? (memberships.get(accountId) ?? null) : null), membershipById: () => Effect.die("tenant authorization does not look up by membership id"), membershipsOf: () => Effect.die("tenant authorization reads one membership, not the list"), members: () => Effect.die("tenant authorization does not list members"), membersById: () => Effect.die("tenant authorization does not batch members"), findByEmail: () => Effect.die("tenant authorization does not resolve emails"), }); // No Authorization header in these tests: the api-key path falls through to // the session path without validating anything. const stubApiKeys = Layer.succeed(ApiKeyService)({ validate: () => Effect.die("no bearer credential is presented"), listUserKeys: () => Effect.die("tenant authorization does not list keys"), createUserKey: () => Effect.die("tenant authorization does not create keys"), revokeUserKey: () => Effect.die("tenant authorization does not revoke keys"), listOrgKeys: () => Effect.die("tenant authorization does not list keys"), createOrgKey: () => Effect.die("tenant authorization does not create keys"), revokeOrgKey: () => Effect.die("tenant authorization does not revoke keys"), }); // The mirror's account row as `ensureAccount` mints it: id only, profile // columns unfilled until a WorkOS user payload arrives. const bareAccount = (id: string) => ({ id, email: null, firstName: null, lastName: null, avatarUrl: null, workosUpdatedAt: null, lastSignInAt: null, createdAt, }); // The selector is an org id, so only `getOrganization` is reached; the org // row is already mirrored. const stubUsers = Layer.succeed(UserStoreService)({ use: (_op, fn) => Effect.promise(() => fn({ ensureAccount: async (id: string) => bareAccount(id), getAccount: async (id: string) => bareAccount(id), upsertOrganization: async (org: { id: string; name: string }) => ({ ...org, slug: org.id, backfilledAt: createdAt, deletedAt: null, workosUpdatedAt: null, createdAt, }), getOrganization: async (id: string) => ({ id, name: `Org ${id}`, slug: id, backfilledAt: createdAt, deletedAt: null, workosUpdatedAt: null, createdAt, }), getOrganizationBySlug: async (slug: string) => ({ id: slug, name: `Org ${slug}`, slug, backfilledAt: createdAt, deletedAt: null, workosUpdatedAt: null, createdAt, }), markOrganizationDeleted: async () => null, deleteOrganizationCascade: async () => {}, }), ), }); // Authorization scans an organization the backfill never covered before it // reads the mirror (`auth/organization.ts`); every org row above is marked // backfilled, so the scan is never reached and the mirror is never written. const stubMirror = Layer.succeed( WorkOsMirror, new Proxy({} as WorkOsMirrorShape, { get: (_target, prop) => () => Effect.die(`unexpected WorkOsMirror.${String(prop)} call`), }), ); // Only session authentication is served; membership is read from the mirror, // so any other WorkOS call fails the test. const stubWorkOS = (userId: string) => Layer.succeed( WorkOSClient, new Proxy({} as WorkOSClientService, { get: (_target, prop) => { if (prop === "authenticateRequest") { return () => Effect.succeed({ userId, email: `${userId}@placeholder.test`, organizationId: null, }); } return () => Effect.die(`unexpected WorkOSClient.${String(prop)} call`); }, }), ); const authorizeAs = (userId: string) => authorizeTenant( new Request("https://admin.invalid", { headers: { cookie: "wos-session=sealed", [ORG_SELECTOR_HEADER]: ORG }, }), ).pipe( Effect.provide( Layer.mergeAll(stubDirectory, stubApiKeys, stubUsers, stubWorkOS(userId), stubMirror), ), ); describe("authorizeTenant ยท admin session", () => { it.effect("an active admin resolves the selected org as the tenant", () => Effect.gen(function* () { const tenant = yield* authorizeAs("user_admin"); expect(tenant).toBe(ORG); }), ); it.effect("an active plain member is forbidden", () => Effect.gen(function* () { const error = yield* Effect.flip(authorizeAs("user_member")); expect(error, "this plane serves the whole tenant; a member is not enough").toBeInstanceOf( AdminUsersForbidden, ); }), ); it.effect("a pending admin invite is forbidden", () => Effect.gen(function* () { const error = yield* Effect.flip(authorizeAs("user_invited_admin")); expect(error, "an admin role that is still pending is not an admin").toBeInstanceOf( AdminUsersForbidden, ); }), ); });