/ test / playwright / podinfo.test.ts
podinfo.test.ts
 1  /**
 2   * Copyright 2025 Defense Unicorns
 3   * SPDX-License-Identifier: AGPL-3.0-or-later OR LicenseRef-Defense-Unicorns-Commercial
 4   */
 5  
 6  import { expect, test } from "@playwright/test";
 7  import { domain } from "./uds.config";
 8  
 9  const podinfoUrl = `https://podinfo.${domain}`;
10  const ssoBaseUrl = `https://sso.${domain}`;
11  
12  // These tests validate the end-user behavior for the podinfo app:
13  // - podinfo.uds.dev is protected by Authservice and requires a login
14  // - the /metrics endpoint is not directly accessible to browsers/unauthenticated callers
15  //
16  // Note: Prometheus -> podinfo scraping is validated separately by the Prometheus Vitest
17  // e2e in test/vitest/prometheus.spec.ts, which asserts that all configured Prometheus
18  // targets (including podinfo monitors) are "up".
19  
20  test.describe("Podinfo Authservice protection and metrics behavior", () => {
21    test("podinfo is protected and login flow works", async ({ browser }) => {
22      const context = await browser.newContext({ storageState: undefined });
23      const page = await context.newPage();
24  
25      try {
26        // Navigate to podinfo without any existing auth state; should redirect to SSO
27        await page.goto(podinfoUrl);
28        await page.waitForLoadState("networkidle");
29  
30        const redirectedUrl = page.url();
31        expect(
32          redirectedUrl.startsWith(`${ssoBaseUrl}/realms/uds/protocol/openid-connect/auth`),
33        ).toBe(true);
34  
35        // Complete the Keycloak login flow
36        await page.getByLabel("Username or email").fill("doug");
37        await page.getByLabel("Password").fill("unicorn123!@#UN");
38        await page.getByRole("button", { name: "Sign In" }).click();
39  
40        // After successful login we should be redirected back to podinfo
41        await page.waitForLoadState("networkidle");
42        await page.waitForURL(new RegExp(`^${podinfoUrl.replace(".", "\\.")}`), {
43          timeout: 30000,
44        });
45  
46        // Basic sanity check that podinfo content is rendered
47        await expect(page).toHaveURL(podinfoUrl, { timeout: 10000 });
48      } finally {
49        await context.close();
50      }
51    });
52  
53    test("unauthenticated access to podinfo metrics is RBAC denied", async ({ browser }) => {
54      const context = await browser.newContext({ storageState: undefined });
55      const page = await context.newPage();
56  
57      try {
58        const metricsUrl = `${podinfoUrl}/metrics`;
59  
60        // Direct unauthenticated request to the metrics endpoint should be denied by Envoy RBAC
61        const response = await page.goto(metricsUrl, { waitUntil: "networkidle" });
62        expect(response).not.toBeNull();
63        expect(response?.status()).toBe(403);
64      } finally {
65        await context.close();
66      }
67    });
68  });