test(e2e): cover Grafana relying-party SSO landing (spec 20)
13-sso proves an authenticated session reaches Grafana login page but never follows the OAuth button, so the relying-party login could be dead (500, or an email-claim gap bouncing to /login) while the suite stayed green. Spec 20 drives /login/generic_oauth through the real Anubis+authentik round-trip and asserts a live session (/api/user 200 with a non-empty email). Wire 20- into the standard project (qa-e2e session).
This commit is contained in:
1 parent
91d9864bb0
commit
200039d589
2 files changed
+60
-2
No files matched your search
@@ -29,8 +29,10 @@ export default defineConfig({
|
|||||||
// green suite with a test that does not exist. 17- joined on 2026-09-16
|
// green suite with a test that does not exist. 17- joined on 2026-09-16
|
||||||
// (the hermes vhost, whose upstream is a host address rather than a
|
// (the hermes vhost, whose upstream is a host address rather than a
|
||||||
// container name, so it needs its own pass condition). 18- joined on
|
// container name, so it needs its own pass condition). 18- joined on
|
||||||
// 2026-09-24 (OpenWebUI SSO through authentik).
|
// 2026-09-24 (OpenWebUI SSO through authentik). 20- joined on 2026-10-21
|
||||||
testMatch: /(10|12|13|16|17|18)-.*\.spec\.ts/,
|
// (Grafana's OAuth2 relying-party login, which the edge-only 13- never
|
||||||
|
// follows).
|
||||||
|
testMatch: /(10|12|13|16|17|18|20)-.*\.spec\.ts/,
|
||||||
use: { storageState: ".auth/qa-e2e.json" },
|
use: { storageState: ".auth/qa-e2e.json" },
|
||||||
dependencies: ["setup"],
|
dependencies: ["setup"],
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -0,0 +1,56 @@
|
|||||||
|
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);
|
||||||
|
});
|
||||||
Reference in new issue
Block a user