import { expect, test } from "@playwright/test"; import { type Consent, installDevApiMock, makeClient, seedAuth, } from "./helpers/devfront-fixtures"; test.describe("DevFront security and isolation", () => { test.beforeEach(async ({ page }) => { page.on("dialog", async (dialog) => { await dialog.accept(); }); await seedAuth(page); }); test("tenant isolation: forbidden client shows blocked error", async ({ page, }) => { const state = { clients: [makeClient("tenant-a-client", { name: "Tenant A app" })], consents: [] as Consent[], auditLogsByCursor: undefined, }; await installDevApiMock(page, state); await page.goto("/clients/tenant-b-client"); await expect(page.getByText(/Error loading client|조회/i)).toBeVisible(); }); test("RBAC: non-AppManager user should not see private apps", async ({ page, }) => { const state = { clients: [ makeClient("pkce-client", { name: "PKCE only app", type: "pkce", }), ], consents: [] as Consent[], auditLogsByCursor: undefined, }; await installDevApiMock(page, state); await page.goto("/clients"); await expect(page.getByText("PKCE only app")).toBeVisible(); await expect(page.getByText("Server side App")).not.toBeVisible(); }); test("tenant_member user is blocked at AuthGuard", async ({ page }) => { await seedAuth(page, "tenant_member"); await page.goto("/clients"); await expect( page.getByText(/DevFront는 관리자 전용 화면입니다|administrator access/i), ).toBeVisible(); await expect(page).toHaveURL(/\/clients$/); }); test("rp_admin receives 403 on clients list and sees ForbiddenMessage", async ({ page, }) => { await seedAuth(page, "rp_admin"); const state = { clients: [] as ReturnType[], consents: [] as Consent[], auditLogsByCursor: undefined, }; await installDevApiMock(page, state); await page.route("**/api/v1/dev/clients", async (route) => { if (route.request().method() === "GET") { return route.fulfill({ status: 403, contentType: "application/json", body: '{"error": "forbidden"}', }); } return route.fallback(); }); await page.goto("/clients"); await expect(page.getByText(/RP 관리자는|RP administrators can only access/i)).toBeVisible(); }); test("tenant_admin receives 403 on audit logs and sees ForbiddenMessage", async ({ page, }) => { await seedAuth(page, "tenant_admin"); const state = { clients: [] as ReturnType[], consents: [] as Consent[], auditLogsByCursor: undefined, }; await installDevApiMock(page, state); await page.route("**/api/v1/dev/audit-logs*", async (route) => { if (route.request().method() === "GET") { return route.fulfill({ status: 403, contentType: "application/json", body: '{"error": "forbidden"}', }); } return route.fallback(); }); await page.goto("/audit-logs"); await expect( page.getByText(/테넌트 관리자 권한|Tenant administrator permissions/i), ).toBeVisible(); }); });