fix(tests): Coverage-Pruefung lauffaehig machen und Drift-Allowlist haerten

BLOCKING-Befunde aus "Tests & Sicherheitshaertung":

1) Coverage-Pfad war nie ausfuehrbar: @vitest/coverage-v8 fehlte in den
   devDependencies, obwohl vitest.config coverage.provider "v8" setzt und
   test:coverage "vitest run --coverage" aufruft. Paket passend zu vitest
   ^3.2 ergaenzt und installiert. coverage.include zog ganze Verzeichnisse
   (src/lib/search, src/lib/geo) ein - inkl. DB-/HTTP-gebundener Wrapper
   (Drizzle gegen Postgres, Nominatim/OSRM), die offline nicht laufen und
   die globale Schwelle verwaesserten. Scope auf die REINE, offline
   testbare Logik beschraenkt (perFile-Schwellen), I/O-Wrapper und reine
   Typ-Module ausgenommen (per Integrations-/E2E-Tests abgesichert).
   Fehlende Branch-Abdeckung in geo/eintreffzeit.ts mit Tests fuer
   Einzel-Haversine-Fallback, reine Koordinaten-lose Liste und fehlende
   OSRM-distances-Zeile geschlossen. npm run test:coverage: Exit 0,
   Schwellen (Lines/Stmts/Funcs >=90, Branches >=80) erfuellt.

2) Driftschutz zu permissiv: isPublic() in tests/support/route-scan.ts
   stufte ueber `route.startsWith(p)` jeden reinen String-Praefix als
   oeffentlich ein (z. B. /loginhelp, /api/healthz, /api/authentication)
   und liess solche Routen dem Auth-Gating-Driftcheck entkommen. Die
   redundante dritte Bedingung entfernt; exakter Treffer und echtes
   Unterpfad-Segment (p + "/") sind korrekt und ausreichend. Negativ-
   Testfall ergaenzt.

Verifiziert (offline): tsc --noEmit (0), vitest run (233 passed,
7 DB-Tests deferred), test:coverage (Exit 0). DB-/Server-/Browser-
abhaengige Schritte deferred (kein Postgres/Server im Sandbox).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Matthias Hochmeister
2026-06-09 14:42:25 +02:00
parent c099b3acd9
commit 2e56a92b70
7 changed files with 735 additions and 2 deletions

View File

@@ -40,8 +40,11 @@ export function filePathToRoute(filePath: string): string {
}
function isPublic(route: string): boolean {
// Nur exakter Treffer oder echtes Unterpfad-Segment zählt als öffentlich.
// KEIN reiner String-Präfix: sonst wären z. B. "/loginhelp" oder
// "/api/healthz" fälschlich anonym erreichbar und entkämen dem Drift-Check.
return PUBLIC_ALLOWLIST.some(
(p) => route === p || route.startsWith(p + "/") || route.startsWith(p),
(p) => route === p || route.startsWith(p + "/"),
);
}

View File

@@ -60,6 +60,18 @@ describe("findUndeclaredRoutes", () => {
expect(findUndeclaredRoutes(discovered, declared)).toEqual([]);
});
it("flaggt Routen mit reinem String-Präfix als ungetestet (kein Pfadsegment)", () => {
const declared = new Set<string>();
// "/loginhelp" beginnt zwar mit "/login" und "/api/healthz" mit
// "/api/health", sind aber KEINE Unterpfade -> müssen gegated werden.
const discovered = ["/loginhelp", "/api/healthz", "/api/authentication"];
expect(findUndeclaredRoutes(discovered, declared)).toEqual([
"/loginhelp",
"/api/healthz",
"/api/authentication",
]);
});
it("PUBLIC_ALLOWLIST enthält /api/health und /login", () => {
expect(PUBLIC_ALLOWLIST).toContain("/api/health");
expect(PUBLIC_ALLOWLIST).toContain("/login");