48acfcd715
Added: wrong-password rejection (local + OIDC), session survives a page reload, and API-level checks that /api/hosts, /api/devices, /api/auth/me all reject unauthenticated requests regardless of what the UI does. No new app bugs found this round -- one test assertion was itself wrong (expected no session cookie on failed login; @fastify/session issues an anonymous cookie on any response by design, that's normal). Fixed to assert the property that actually matters: the cookie grants no access. 9/9 tests green across 4 consecutive full-suite runs with parallel workers, no flakiness. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
54 lines
2.4 KiB
TypeScript
54 lines
2.4 KiB
TypeScript
import { test, expect } from "@playwright/test";
|
|
|
|
const USERNAME = process.env.OIDC_USERNAME ?? "playwright-test";
|
|
const PASSWORD = process.env.OIDC_PASSWORD ?? "";
|
|
|
|
test("OIDC login via Authentik stays on public domains throughout", async ({ page }) => {
|
|
test.skip(!PASSWORD, "OIDC_PASSWORD not set");
|
|
|
|
await page.goto("/");
|
|
const oidcButton = page.getByRole("link", { name: "Sign in with Authentik" });
|
|
await expect(oidcButton).toBeVisible();
|
|
await oidcButton.click();
|
|
|
|
// Regression check for the actual bug reported: the authorization endpoint
|
|
// must be the public auth.jerodrigged.com, never a LAN IP a browser off the
|
|
// LAN can't reach.
|
|
await page.waitForURL(/^https:\/\/auth\.jerodrigged\.com\//, { timeout: 10_000 });
|
|
expect(page.url()).not.toMatch(/192\.168\./);
|
|
|
|
await page.getByPlaceholder(/email or username/i).fill(USERNAME);
|
|
await page.getByRole("button", { name: /log in|continue|next/i }).click();
|
|
|
|
// Authentik's password field has no <label> association -- it's identified
|
|
// by placeholder text ("Please enter your password"), not an a11y label.
|
|
await page.getByPlaceholder(/password/i).fill(PASSWORD);
|
|
await page.getByRole("button", { name: /log in|continue|sign in/i }).click();
|
|
|
|
await page.waitForURL(/^https:\/\/monitor\.jerodrigged\.com\//, { timeout: 15_000 });
|
|
expect(page.url()).not.toMatch(/192\.168\./);
|
|
|
|
await expect(page.locator(".host-card").first()).toBeVisible({ timeout: 15_000 });
|
|
|
|
await page.getByRole("button", { name: "Sign out" }).click();
|
|
await expect(page.getByPlaceholder("Username")).toBeVisible();
|
|
});
|
|
|
|
test("wrong Authentik password does not reach the dashboard", async ({ page }) => {
|
|
test.skip(!PASSWORD, "OIDC_PASSWORD not set");
|
|
|
|
await page.goto("/");
|
|
await page.getByRole("link", { name: "Sign in with Authentik" }).click();
|
|
await page.waitForURL(/^https:\/\/auth\.jerodrigged\.com\//, { timeout: 10_000 });
|
|
|
|
await page.getByPlaceholder(/email or username/i).fill(USERNAME);
|
|
await page.getByRole("button", { name: /log in|continue|next/i }).click();
|
|
|
|
await page.getByPlaceholder(/password/i).fill("definitely-not-the-password");
|
|
await page.getByRole("button", { name: /log in|continue|sign in/i }).click();
|
|
|
|
// Authentik re-shows the password stage with an error, never redirects back.
|
|
await expect(page.getByText(/failed|invalid|incorrect/i)).toBeVisible({ timeout: 10_000 });
|
|
expect(page.url()).toMatch(/^https:\/\/auth\.jerodrigged\.com\//);
|
|
});
|