Beweist die Auth-Gating-Garantie und härtet das System ab (Definition of Done #1, #2, #3, #7, #8): - Routen-Manifest (tests/e2e/routes.manifest.ts) als einzige Quelle der Wahrheit; anonyme Seite -> Redirect /login, anonyme API -> 401. - Kritische auth-gating.spec.ts: genau ein Fall je Manifest-Eintrag, ohne Daten-Leak. - Driftschutz (routes.manifest.spec.ts + tests/unit/routes-manifest.test.ts): keine ungetestete neue Route unter src/app/**. - Default-Deny-Beweis für Server Actions (server-actions-guard.spec.ts + tests/unit/server-actions-guard.test.ts): jede "use server"-Funktion ruft als erste Anweisung einen Guard; Login-Actions per Allowlist ausgenommen. - Wiederverwendbare reine Scanner unter tests/support (route-scan, guard-scan) — offline lauffähig, in Vitest und Playwright geteilt. - rbac-scoping, search-eta, login-ratelimit, security-headers Specs (gegen geseedeten Server; in der Sandbox deferred, per test.skip abgesichert). - global-setup (Migration + Seed) und auth.setup (Login je Konto -> storageState); Playwright-Projekte setup -> chromium verdrahtet. - src/lib/security/headers.test.ts: statischer Beleg für CSP, HSTS, X-Frame-Options DENY, nosniff, Permissions-Policy. - vitest.config.ts: Coverage-Schwellen (>=90 %) für src/lib/search + src/lib/geo. - package.json: Scripts test:unit, test:coverage, test:e2e, test:e2e:gating. - docs/reference/sicherheitshaertung-checkliste.md: jeder Härtungspunkt mit Test/Befehl und Negativ-Probe. Offline verifiziert: tsc --noEmit (0), vitest run (229 passed / 7 db-skipped), drizzle-kit check (ok), next build (exit 0), next lint (0 Fehler), playwright --list (98 Tests, 15 Dateien). DB-/Server-/Browser-abhängige E2E-Läufe sind deferred (kein Postgres/Server in der Sandbox). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
42 lines
1.4 KiB
TypeScript
42 lines
1.4 KiB
TypeScript
import { defineConfig, devices } from "@playwright/test";
|
|
|
|
/**
|
|
* Playwright-Konfiguration für die Auth-Gating-Suite.
|
|
*
|
|
* HINWEIS: Diese Suite erfordert einen LAUFENDEN Server (Next.js) und eine
|
|
* erreichbare Datenbank. In der Sandbox/CI ohne Server/DB wird sie NICHT
|
|
* ausgeführt (deferred). `webServer` startet die App lokal, wenn vorhanden.
|
|
*/
|
|
export default defineConfig({
|
|
testDir: "./tests/e2e",
|
|
fullyParallel: true,
|
|
forbidOnly: !!process.env.CI,
|
|
retries: process.env.CI ? 2 : 0,
|
|
reporter: process.env.CI ? "github" : "list",
|
|
// Migration + deterministischer Seed (deferred ohne DATABASE_URL).
|
|
globalSetup: "./tests/e2e/global-setup.ts",
|
|
use: {
|
|
baseURL: process.env.E2E_BASE_URL ?? "http://localhost:3000",
|
|
trace: "on-first-retry",
|
|
},
|
|
projects: [
|
|
// 1. Echter Login je Konto -> storageState (tests/e2e/.auth/*.json).
|
|
{ name: "setup", testMatch: /fixtures\/auth\.setup\.ts/ },
|
|
// 2. Eigentliche Suiten; hängen vom Login-Setup ab.
|
|
{
|
|
name: "chromium",
|
|
use: { ...devices["Desktop Chrome"] },
|
|
testIgnore: /fixtures\/auth\.setup\.ts/,
|
|
dependencies: ["setup"],
|
|
},
|
|
],
|
|
webServer: process.env.E2E_BASE_URL
|
|
? undefined
|
|
: {
|
|
command: "npm run build && npm run start",
|
|
url: "http://localhost:3000/api/health",
|
|
reuseExistingServer: !process.env.CI,
|
|
timeout: 120_000,
|
|
},
|
|
});
|