147 lines · 5.3 KB · TypeScript
RawDownload
import { describe, expect, it } from "@effect/vitest";import { Effect, Layer } from "effect"; import { ApiKeyService } from "./api-keys";import { UserStoreService } from "./context";import { resolveSessionPrincipal } from "./workos-auth-provider";import { WorkOSClient, type WorkOSClientService } from "./workos"; // The org a console request resolves to is the URL's org (sent in the// `x-executor-organization` selector header) — NEVER the session's stored org.// The sealed cookie's org is a browser-global pinned to whichever org WorkOS// last touched, so a fallback to it silently scopes a multi-org user's request// to the wrong org; a header-less request fails closed instead. Live// membership is re-checked either way. This is what makes two browser tabs on// different orgs independent. const createdAt = new Date("2026-01-01T00:00:00.000Z"); // user_session belongs to BOTH orgs; the URL selects which one a request hits.const MEMBER = "user_session";const SESSION_ORG = "org_session";const URL_ORG = "org_url";const URL_SLUG = "acme"; const stubApiKeys = Layer.succeed(ApiKeyService)({  // No Authorization header in these tests → the api-key path returns null and  // resolution falls through to the session path.  validate: () => Effect.succeed(null),  listUserKeys: () => Effect.succeed([]),  createUserKey: () => Effect.die("not used"),  revokeUserKey: () => Effect.void,  listOrgKeys: () => Effect.die("auth resolution test does not list org API keys"),  createOrgKey: () => Effect.die("auth resolution test does not create org API keys"),}); const stubWorkOS = Layer.succeed(  WorkOSClient,  new Proxy({} as WorkOSClientService, {    get: (_t, prop) => {      if (prop === "authenticateRequest") {        return () =>          Effect.succeed({            userId: MEMBER,            email: "u@e2e.test",            organizationId: SESSION_ORG,          });      }      if (prop === "listUserMemberships") {        return (userId: string) =>          Effect.succeed({            data:              userId === MEMBER                ? [                    { userId, organizationId: SESSION_ORG, status: "active" },                    { userId, organizationId: URL_ORG, status: "active" },                  ]                : [],          });      }      return () => Effect.die(`unexpected WorkOSClient.${String(prop)} call`);    },  }),); const stubUsers = Layer.succeed(UserStoreService)({  use: (fn) =>    Effect.promise(() =>      fn({        ensureAccount: async (id: string) => ({ id, createdAt }),        getAccount: async (id: string) => ({ id, createdAt }),        // Slug is minted at insert now — the stub returns a slugged row.        upsertOrganization: async (org: { id: string; name: string }) => ({          ...org,          slug: org.id,          createdAt,        }),        getOrganization: async (id: string) => ({          id,          name: `Org ${id}`,          slug: id,          createdAt,        }),        // The URL slug maps to URL_ORG (the member's other org); any other slug        // maps to an org the caller is NOT a member of, so membership rejects it.        getOrganizationBySlug: async (slug: string) => ({          id: slug === URL_SLUG ? URL_ORG : "org_outsider",          name: `Org ${slug}`,          slug,          createdAt,        }),        deleteOrganizationCascade: async () => {},      }),    ),}); const run = (headers: Record<string, string>) =>  resolveSessionPrincipal(new Request("https://executor.test/api/tools", { headers })).pipe(    Effect.provide(Layer.mergeAll(stubApiKeys, stubWorkOS, stubUsers)),  ); describe("resolveSessionPrincipal · URL org selector", () => {  it.effect("fails closed when no selector header is sent", () =>    Effect.gen(function* () {      // No fallback to the session org: the cookie's org is browser-global      // and can name a different org than the tab's URL for a multi-org user.      const error = yield* Effect.flip(run({ cookie: "wos-session=x" }));      expect(error, "rejects instead of scoping to the session org").toMatchObject({        _tag: "NoOrganization",        code: "no_organization",      });    }),  );   it.effect("scopes to the URL org (by slug) over the session org", () =>    Effect.gen(function* () {      const principal = yield* run({        cookie: "wos-session=x",        "x-executor-organization": URL_SLUG,      });      expect(principal.organizationId, "the slug header wins over the session org").toBe(URL_ORG);    }),  );   it.effect("accepts a WorkOS org id as the selector too", () =>    Effect.gen(function* () {      const principal = yield* run({        cookie: "wos-session=x",        "x-executor-organization": URL_ORG,      });      expect(principal.organizationId).toBe(URL_ORG);    }),  );   it.effect("rejects a selector for an org the caller is not a member of", () =>    Effect.gen(function* () {      // The slug resolves to a real org id, but membership is re-checked — a      // slug is a selector, not a trust boundary, so a non-member is rejected.      const error = yield* Effect.flip(        run({          cookie: "wos-session=x",          "x-executor-organization": "outsider-slug",        }),      );      expect(error).toMatchObject({ _tag: "NoOrganization" });    }),  );});