16-marreta.spec.ts (standard project) asserts the user homepage's Marreta open link actually reaches the Marreta app through the full guard chain (Anubis PoW -> Authentik SSO -> app), and explicitly NOT the authentik login flow. Guards the 2026-09-12 incident where marreta-proxy was created without a linked Application, so the embedded outpost never loaded it and the homepage link parked on a login wall. Wires spec 16 into the standard project testMatch. Verified passing live.
66 lines
2.7 KiB
TypeScript
66 lines
2.7 KiB
TypeScript
import { expect, test } from "@playwright/test";
|
|
|
|
// Regression guard for the 2026-09-12 incident. The homepage's Marreta tile
|
|
// resolved to the authentik login flow instead of the app: the `marreta-proxy`
|
|
// ProxyProvider had been created without a linked authentik Application, so the
|
|
// embedded outpost's config API
|
|
// (`ProxyProvider.objects.filter(application__isnull=False)`) never returned it,
|
|
// the Rust outpost never loaded the provider, and the request fell through to
|
|
// raw flow serving on the marreta host — where the IdP session cookie (scoped
|
|
// to auth.franksdank.cloud) is invisible, so login was demanded.
|
|
//
|
|
// This test proves the homepage link actually reaches the Marreta app through
|
|
// the full guard chain (Anubis PoW -> Authentik SSO -> app), and that it does
|
|
// NOT park on a login wall.
|
|
|
|
const CHALLENGE = "Making sure you're not a bot";
|
|
const MARRETA_HOST = "marreta.franksdank.cloud";
|
|
|
|
test("Marreta homepage tile reaches the Marreta app, not a login wall", async ({ page }) => {
|
|
test.setTimeout(150_000);
|
|
|
|
// 1. The user homepage must expose exactly one Marreta open link, and it must
|
|
// target the marreta vhost (not a docs stub or a wrong host).
|
|
await page.goto("/");
|
|
const marretaPanel = page
|
|
.locator("#grid .panel")
|
|
.filter({ has: page.locator(".name", { hasText: "Marreta" }) });
|
|
await expect(marretaPanel, "exactly one Marreta panel on the user grid").toHaveCount(1);
|
|
|
|
const openLink = marretaPanel.locator("a.open");
|
|
await expect(openLink, "Marreta panel must have an open link").toHaveCount(1);
|
|
const href = await openLink.getAttribute("href");
|
|
expect(href, "Marreta open link must target the marreta vhost").toMatch(
|
|
new RegExp(`marreta\\.franksdank\\.cloud`),
|
|
);
|
|
|
|
// 2. Follow the link through the guard chain and wait out the Anubis PoW.
|
|
await page.goto(href!);
|
|
await expect
|
|
.poll(async () => !(await page.locator("body").innerText()).includes(CHALLENGE), {
|
|
timeout: 90_000,
|
|
})
|
|
.toBe(true);
|
|
|
|
// 3. Must land on the Marreta app — NOT the authentik login flow.
|
|
const finalUrl = new URL(page.url());
|
|
expect(finalUrl.hostname, "must stay on the marreta host").toBe(MARRETA_HOST);
|
|
expect(
|
|
finalUrl.pathname,
|
|
"must not be parked on an authentik flow / outpost start page",
|
|
).not.toMatch(/\/(if|flows)\/|\/outpost\.goauthentik\.io\/start/);
|
|
expect(
|
|
await page.locator('input[name="uidField"]').count(),
|
|
"must not show the authentik login form",
|
|
).toBe(0);
|
|
|
|
// 4. Positive identity: the page really is Marreta.
|
|
await expect(page, "destination title must be Marreta").toHaveTitle(/marreta/i, {
|
|
timeout: 30_000,
|
|
});
|
|
await expect(page.locator("body"), "Marreta app marker").toContainText(
|
|
/paywall-free reading/i,
|
|
{ timeout: 30_000 },
|
|
);
|
|
});
|