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>
66 lines
1.9 KiB
JSON
66 lines
1.9 KiB
JSON
{
|
|
"name": "floriannetz",
|
|
"version": "0.1.0",
|
|
"private": true,
|
|
"type": "module",
|
|
"scripts": {
|
|
"dev": "next dev",
|
|
"build": "next build",
|
|
"start": "next start",
|
|
"lint": "next lint",
|
|
"typecheck": "tsc --noEmit",
|
|
"test": "vitest run",
|
|
"test:watch": "vitest",
|
|
"test:unit": "vitest run",
|
|
"test:coverage": "vitest run --coverage",
|
|
"db:generate": "drizzle-kit generate",
|
|
"db:migrate": "tsx scripts/migrate.ts",
|
|
"db:seed-auth": "tsx scripts/seed-auth.ts",
|
|
"db:seed": "tsx src/db/seed/index.ts",
|
|
"test:e2e": "playwright test",
|
|
"test:e2e:gating": "playwright test --project=chromium tests/e2e/auth-gating.spec.ts",
|
|
"db:push": "drizzle-kit push",
|
|
"db:studio": "drizzle-kit studio",
|
|
"db:check": "drizzle-kit check"
|
|
},
|
|
"dependencies": {
|
|
"@node-rs/argon2": "^2.0.2",
|
|
"@radix-ui/react-dialog": "^1.1.6",
|
|
"@radix-ui/react-label": "^2.1.2",
|
|
"@radix-ui/react-select": "^2.1.6",
|
|
"@radix-ui/react-slider": "^1.2.3",
|
|
"@radix-ui/react-slot": "^1.1.2",
|
|
"@radix-ui/react-switch": "^1.1.3",
|
|
"@radix-ui/react-tabs": "^1.1.3",
|
|
"class-variance-authority": "^0.7.1",
|
|
"clsx": "^2.1.1",
|
|
"drizzle-orm": "^0.39.3",
|
|
"next": "^15.2.0",
|
|
"next-auth": "^5.0.0-beta.31",
|
|
"pg": "^8.13.3",
|
|
"react": "^19.0.0",
|
|
"react-dom": "^19.0.0",
|
|
"tailwind-merge": "^3.0.2",
|
|
"zod": "^3.24.2"
|
|
},
|
|
"devDependencies": {
|
|
"@eslint/eslintrc": "^3.2.0",
|
|
"@playwright/test": "^1.60.0",
|
|
"@types/node": "^22.13.5",
|
|
"@types/pg": "^8.11.11",
|
|
"@types/react": "^19.0.10",
|
|
"@types/react-dom": "^19.0.4",
|
|
"autoprefixer": "^10.4.20",
|
|
"drizzle-kit": "^0.30.4",
|
|
"eslint": "^9.21.0",
|
|
"eslint-config-next": "^15.2.0",
|
|
"postcss": "^8.5.3",
|
|
"prettier": "^3.5.2",
|
|
"prettier-plugin-tailwindcss": "^0.6.11",
|
|
"tailwindcss": "^3.4.17",
|
|
"tsx": "^4.19.2",
|
|
"typescript": "^5.7.3",
|
|
"vitest": "^3.0.7"
|
|
}
|
|
}
|