142 lines · 6.4 KB · TypeScript
RawDownload
// Cloud-only: the Organization keys SECTION of the API keys page — the console// surface over `/api/account/org-api-keys`, minting the machine credential for// the tenant-wide admin plane.//// Two members are built through the real flows. The guarantees pinned here:////   1. an ADMIN sees the section, mints an org key through the dialog, gets the//      one-time reveal, and the minted value ACTUALLY authenticates the admin//      API (the whole point of the credential);//   2. the listing shows the key afterward and revoke asks for confirmation//      before killing it — after which the value stops authenticating;//   3. a PLAIN MEMBER never sees the section at all.//// Runs against emulate >= 0.13.9, whose WorkOS emulator serves the org-key// routes (list/mint via /organizations/:id/api_keys, org-owner validation) —// the gap that previously kept this scenario impossible.import { expect } from "@effect/vitest";import { Effect } from "effect"; import { scenario } from "../src/scenario";import { Browser, Target } from "../src/services";import { forBrowser, joinOrg } from "./support/session";import { visit } from "../src/surfaces/browser"; declare global {  interface Window {    __e2eCopied?: Array<string>;  }} scenario(  "Admin · organization keys are minted in the console and authenticate the admin API",  { timeout: 180_000 },  Effect.gen(function* () {    const target = yield* Target;    const browser = yield* Browser;     const admin = yield* target.newIdentity();    const invitee = yield* target.newIdentity({ org: false });    const member = yield* joinOrg(target, admin, invitee);     let mintedValue = "";     // ── The admin's view: mint, verify, revoke ──────────────────────────────    yield* browser.session(forBrowser(admin), async ({ page, step }) => {      let slug = "";       await step("Land in the workspace and open the API keys page", async () => {        await visit(page, "/");        await page.waitForURL((url) => /^\/[a-z0-9-]+\/?$/.test(url.pathname), {          timeout: 30_000,        });        slug = new URL(page.url()).pathname.split("/").filter(Boolean)[0] ?? "";        await page.getByRole("link", { name: "API keys" }).click();        await page.waitForURL((url) => url.pathname === `/${slug}/api-keys`, { timeout: 30_000 });      });       await step("The admin is offered the Organization keys section", async () => {        await page          .getByRole("heading", { name: "Organization keys", exact: true })          .waitFor({ state: "visible", timeout: 30_000 });      });       await step("Mint an org key through the dialog and capture the reveal", async () => {        await page.getByRole("button", { name: "New org key" }).click();        const dialog = page.getByRole("dialog");        await dialog.getByLabel("Name").fill("e2e backend reader");        await dialog.getByRole("button", { name: "Create key" }).click();         // The one-time secret panel renders once the key exists; its first        // input holds the plaintext value (same shape the personal-key        // feedback scenario reads).        await dialog.getByText("It is only shown once").waitFor({ timeout: 30_000 });        mintedValue = await dialog.locator("input").first().inputValue();        expect(mintedValue, "a real key value is revealed once").toMatch(/^sk_/);        await dialog.getByRole("button", { name: "Close", exact: true }).first().click();      });       await step("The minted key appears in the org listing", async () => {        await page          .getByText("e2e backend reader")          .first()          .waitFor({ state: "visible", timeout: 30_000 });      });       await step("The minted value authenticates the tenant-wide admin API", async () => {        // The credential's purpose, proven from outside the browser: a backend        // holding ONLY this value can read the admin plane.        const response = await fetch(new URL("/api/admin/users", target.baseUrl), {          headers: { authorization: `Bearer ${mintedValue}` },        });        expect(response.status, "the org key reads the admin plane").toBe(200);        const body = (await response.json()) as {          users: ReadonlyArray<{ email: string | null }>;        };        expect(          body.users.map((user) => user.email),          "and sees the workspace's members",        ).toContain(admin.credentials?.email);      });       await step("Revoke asks for confirmation, then the key stops working", async () => {        await page.getByRole("button", { name: "Revoke e2e backend reader" }).click();        // The confirm dialog names the key and warns; nothing is revoked yet.        await page          .getByRole("heading", { name: "Revoke organization key" })          .waitFor({ state: "visible", timeout: 30_000 });        await page.getByRole("button", { name: "Revoke key" }).click();        await page          .getByRole("heading", { name: "Revoke organization key" })          .waitFor({ state: "hidden", timeout: 30_000 });         // The revoked value no longer authenticates.        const after = await fetch(new URL("/api/admin/users", target.baseUrl), {          headers: { authorization: `Bearer ${mintedValue}` },        });        expect(after.status, "the revoked key is refused").toBe(401);      });    });     // ── The plain member's view ───────────────────────────────────────────    yield* browser.session(forBrowser(member), async ({ page, step }) => {      await step("A plain member is not shown the Organization keys section", async () => {        await visit(page, "/");        await page.waitForURL((url) => /^\/[a-z0-9-]+\/?$/.test(url.pathname), {          timeout: 30_000,        });        const slug = new URL(page.url()).pathname.split("/").filter(Boolean)[0] ?? "";        await visit(page, `/${slug}/api-keys`);        // The personal half renders for everyone…        await page          .getByRole("heading", { name: "Personal keys" })          .waitFor({ state: "visible", timeout: 30_000 });        // …the org section does not exist for a non-admin.        expect(          await page.getByRole("heading", { name: "Organization keys", exact: true }).count(),          "a plain member is not shown a section that would only refuse them",        ).toBe(0);      });    });  }),);