feat:Fix the bootstrap to be deploy key application

This commit is contained in:
Story Crater Bot
2026-08-18 15:08:03 -07:00
parent eac3a2a227
commit 54fa540b33
37 changed files with 1216 additions and 1202 deletions
+32
View File
@@ -0,0 +1,32 @@
import { test, expect } from '@playwright/test';
import { TARGETS, url } from '../targets';
const t = TARGETS.find((x) => x.name === 'authentik')!;
// Authentik: the real signal. A healthy pod does NOT prove OIDC/redirect/session
// work — only a completed sign-in does. Credentials come from env (injected from
// the secret store in-cluster), never hardcoded.
const USER = process.env.AK_ADMIN_USER ?? 'akadmin';
const PASS = process.env.AK_ADMIN_PASSWORD;
test('authentik admin can sign in', async ({ page }) => {
test.skip(!PASS, 'AK_ADMIN_PASSWORD not set — provide via secret to run the login flow');
await page.goto(url(t), { waitUntil: 'domcontentloaded' });
// Authentik identification stage: username, Enter/continue, then password.
const uid = page.locator('input[name="uidField"], input[type="text"], input[type="email"]').first();
await expect(uid).toBeVisible();
await uid.fill(USER);
await page.keyboard.press('Enter');
const pw = page.locator('input[type="password"]').first();
await expect(pw).toBeVisible();
await pw.fill(PASS!);
await page.keyboard.press('Enter');
// Landed on the user dashboard — no auth error banner.
await expect(page).toHaveURL(/\/if\/user|\/if\/admin|\/library/i, { timeout: 20_000 });
await expect(page.getByText(/invalid|incorrect|failed/i)).toHaveCount(0);
await page.screenshot({ path: 'test-results/authentik-dashboard.png', fullPage: true });
});
+47
View File
@@ -0,0 +1,47 @@
import { test, expect } from '@playwright/test';
import { OAUTH_TARGETS, url, BASE_DOMAIN } from '../targets';
import { completeAuthentikLogin } from '../helpers/authentik';
// OIDC/OAuth federation flow — the real SSO integration signal. A healthy app pod
// does NOT prove SSO works: client mis-registration, redirect-URI mismatch, issuer
// cert, or a broken Authentik provider all fail HERE, not at the pod. Each test:
// 1. open the app,
// 2. click its "sign in via Authentik" control,
// 3. complete the Authentik login on the redirect,
// 4. assert we return to the app authenticated.
const USER = process.env.AK_ADMIN_USER ?? 'akadmin';
const PASS = process.env.AK_ADMIN_PASSWORD;
for (const t of OAUTH_TARGETS) {
test(`${t.name} SSO login via Authentik`, async ({ page }) => {
test.skip(!PASS, 'AK_ADMIN_PASSWORD not set — provide via secret to run OAuth flows');
await page.goto(url(t), { waitUntil: 'domcontentloaded' });
// Click the SSO control.
const b = t.ssoButton;
const btn = b.selector
? page.locator(b.selector).first()
: page.getByRole((b.role as any) ?? 'link', { name: b.name! }).first();
await expect(btn, `${t.name}: SSO login control not found`).toBeVisible();
await btn.click();
// We should be redirected to the Authentik domain (or already have a session).
await page.waitForLoadState('domcontentloaded');
if (page.url().includes(`.${BASE_DOMAIN}`) && /authentik|\/if\/flow/i.test(page.url())) {
await completeAuthentikLogin(page, USER, PASS!);
} else {
// Not obviously on Authentik — still attempt, in case creds render inline.
await completeAuthentikLogin(page, USER, PASS!).catch(() => {});
}
// Back in the app, authenticated.
const s = t.success;
if (s.urlRe) await expect(page).toHaveURL(s.urlRe, { timeout: 25_000 });
if (s.selector) await expect(page.locator(s.selector).first()).toBeVisible({ timeout: 25_000 });
if (s.text) await expect(page.getByText(s.text).first()).toBeVisible({ timeout: 25_000 });
await expect(page.getByText(/invalid|unauthorized|access denied|redirect_uri/i)).toHaveCount(0);
await page.screenshot({ path: `test-results/oauth-${t.name}.png`, fullPage: true });
});
}
+14
View File
@@ -0,0 +1,14 @@
import { test, expect } from '@playwright/test';
import { TARGETS, url } from '../targets';
const t = TARGETS.find((x) => x.name === 'portainer')!;
// Portainer: prove the login UI renders over real ingress+TLS in Safari's engine.
// (Full authenticated flow needs an initial-admin password; add once seeded.)
test('portainer login page renders', async ({ page }) => {
const resp = await page.goto(url(t), { waitUntil: 'domcontentloaded' });
expect(resp?.status(), 'ingress did not serve portainer').toBeLessThan(400);
await expect(page.locator('input[type="password"]').first()).toBeVisible();
await page.screenshot({ path: 'test-results/portainer-login.png', fullPage: true });
});
+33
View File
@@ -0,0 +1,33 @@
import { test, expect } from '@playwright/test';
import { TARGETS, url } from '../targets';
// Core assertion the user asked for: once ingress-nginx is up and the app is
// ready, NAME-APP.<domain> must be VIEWABLE in Safari's engine — not just return
// a status code. We navigate, assert a real 2xx/3xx (not nginx 404/503 default
// backend), and assert the app's own UI actually rendered.
// Only apps without a dedicated flow spec (auth logins live in their own file).
const smokeTargets = TARGETS.filter((t) => !t.dedicated);
for (const t of smokeTargets) {
test(`${t.name} is viewable at ${url(t)}`, async ({ page }) => {
const resp = await page.goto(url(t), { waitUntil: 'domcontentloaded' });
expect(resp, 'no response from ingress').toBeTruthy();
const status = resp!.status();
expect(status, `unexpected HTTP status ${status}`).toBeLessThan(400);
// Not the nginx default backend / error page.
await expect(page.locator('body')).not.toContainText(/default backend - 404|503 Service Temporarily/i);
// App's own UI rendered.
const r = t.ready;
if (r.selector) {
await expect(page.locator(r.selector).first()).toBeVisible();
} else if (r.role && r.name) {
await expect(page.getByRole(r.role as any, { name: r.name }).first()).toBeVisible();
} else if (r.text) {
await expect(page.getByText(r.text).first()).toBeVisible();
}
});
}