import { expect, test } from "@playwright/test"; // Grafana (grafana.franksdank.cloud) is an OAuth2 RELYING PARTY, not an // outpost-fronted proxy: the guard chain (13-sso) only proves an authenticated // session reaches Grafana's login page. The login itself happens through // Grafana's own "Sign in with Authentik" button, which the edge test never // follows — that is exactly how the RP login could be dead (500 on authorize, // or an email-claim gap bouncing back to /login) while 13- still passed green. // This spec drives the real RP round-trip and asserts a live Grafana session. const HOST = "grafana.franksdank.cloud"; const CHALLENGE = "Making sure you're not a bot"; test("SSO: Grafana relying-party login lands a real session", async ({ page, request }) => { test.setTimeout(180_000); // Warm the guard: the vhost runs its own Anubis proof-of-work on first visit. await page.goto(`https://${HOST}/`); await expect .poll( async () => !(await page.locator("body").innerText()).includes(CHALLENGE), { timeout: 90_000 }, ) .toBe(true); // The "Sign in with Authentik" button targets this RP start URL exactly. // Going straight there is the same code path without depending on the SPA's // button markup. await page.goto(`https://${HOST}/login/generic_oauth`); // The chain: grafana -> auth (implicit consent, the session is already // there) -> back to grafana with the code -> grafana provisions the user and // redirects to "/". A dead provider/claims config bounces back to /login. await expect .poll( async () => { const u = new URL(page.url()); return u.hostname === HOST && u.pathname !== "/login"; }, { timeout: 90_000 }, ) .toBe(true); const body = await page.locator("body").innerText(); expect(body).not.toContain("Login failed"); expect(body.toLowerCase()).not.toContain("powered by authentik"); // IdP flow shell expect(body).not.toContain(CHALLENGE); // A genuine logged-in session exists: /api/user answers 200 with an email, // not 401. This is the assertion the edge-only spec could never make. const resp = await page.request.get(`https://${HOST}/api/user`); expect(resp.status()).toBe(200); const user = await resp.json(); expect(typeof user.email).toBe("string"); expect(user.email.length).toBeGreaterThan(0); });