docs(15): WINDOWS #10 geschlossen — Browser-Gegenprobe nach dem Fix bestanden

Der am Vormittag gefundene Zugriffs-Guard-Defekt ist behoben (260907-e8k) und im
echten Browser gegen ein frisch gebautes Web-Image nachgeprueft.

nutzer2 ohne Freigabe bekommt jetzt auf /modules/tender-radar, dessen Unterseiten
my-sources und settings sowie auf /modules/dkv-fleet die 403-Seite als
Serverantwort. Auf /modules/cert-manager, wo er eine Freigabe hat, kommt er
weiterhin durch — das ist die Gegenprobe dagegen, dass die Sperre zu weit greift.
admin sieht alle vier Adressen unveraendert, nutzer1 sieht Meine Quellen mit allen
drei Abschnitten; die Phase-17-Funktion ist unbeschaedigt.

Im Bericht zusaetzlich festgehalten, dass ein erster Messversuch per fetch() aus der
laufenden Seite heraus faelschlich alle Seiten als gesperrt meldete, auch fuer den
Administrator. Der Aufruf fuehrt die Sitzung nicht wie eine echte Navigation mit.
Alle berichteten Zahlen stammen aus echten Seitenaufrufen.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K5jtbGzC5Sf9npJ3JCjKhq
This commit is contained in:
2026-09-07 10:40:48 +02:00
parent 9e5445e6b7
commit 0645cac618
3 changed files with 38 additions and 12 deletions
+6 -6
View File
@@ -1,10 +1,10 @@
--- ---
schema_version: 1 schema_version: 1
open_count: 5 open_count: 4
waived_count: 0 waived_count: 0
fixed_count: 7 fixed_count: 8
total_count: 12 total_count: 12
last_updated: 2026-09-07T08:09:04.406Z last_updated: 2026-09-07T08:40:04.951Z
--- ---
# Broken Windows Ledger # Broken Windows Ledger
@@ -24,7 +24,7 @@ last_updated: 2026-09-07T08:09:04.406Z
| 7 | 17 | unrun-verify | .planning/phases/17-eigene-ausschreibungs-quellen-je-nutzer/17-01-PLAN.md | | 17-01 Task 2 human-check: Browser-Gegenprobe (normaler Nutzer oeffnet /modules/tender-radar/my-sources, speichert Postfach, zweites Konto desselben Mandanten sieht leeres Formular) nicht ausgefuehrt — kein Browser-Tool in dieser Session verfuegbar. Automatisierte Pruefungen (prisma validate/migrate status, Index-Liste, beide Typpruefungen, 335/335 src/tenders-Tests) sind gelaufen und gruen. | fixed | | 2026-08-12T09:24:35.289Z | 2026-09-07T07:50:56.468Z | | 7 | 17 | unrun-verify | .planning/phases/17-eigene-ausschreibungs-quellen-je-nutzer/17-01-PLAN.md | | 17-01 Task 2 human-check: Browser-Gegenprobe (normaler Nutzer oeffnet /modules/tender-radar/my-sources, speichert Postfach, zweites Konto desselben Mandanten sieht leeres Formular) nicht ausgefuehrt — kein Browser-Tool in dieser Session verfuegbar. Automatisierte Pruefungen (prisma validate/migrate status, Index-Liste, beide Typpruefungen, 335/335 src/tenders-Tests) sind gelaufen und gruen. | fixed | | 2026-08-12T09:24:35.289Z | 2026-09-07T07:50:56.468Z |
| 8 | 17 | unrun-verify | apps/web/src/app/(portal)/modules/tender-radar/my-sources/page.tsx | | Browser-Gegenprobe Plan 17-03 Task 1 (Tracer-Feedback-Gate): Meine Quellen mit drei Abschnitten, neu angelegter eigener Feed sofort sichtbar, plattformweiter Feed ohne Entfernen-Knopf, Digest-Intervall speichert nach Reload — kein Browser-Tool in dieser Sitzung verfuegbar | fixed | | 2026-08-12T10:02:49.122Z | 2026-09-07T07:50:56.693Z | | 8 | 17 | unrun-verify | apps/web/src/app/(portal)/modules/tender-radar/my-sources/page.tsx | | Browser-Gegenprobe Plan 17-03 Task 1 (Tracer-Feedback-Gate): Meine Quellen mit drei Abschnitten, neu angelegter eigener Feed sofort sichtbar, plattformweiter Feed ohne Entfernen-Knopf, Digest-Intervall speichert nach Reload — kein Browser-Tool in dieser Sitzung verfuegbar | fixed | | 2026-08-12T10:02:49.122Z | 2026-09-07T07:50:56.693Z |
| 9 | 17 | unrun-verify | apps/web/src/app/(portal)/modules/tender-radar/settings/page.tsx | | Browser-Gegenprobe Plan 17-03 Task 2: USER-Konto sieht keine Bedienelemente auf /settings (nur Hinweis+Verweis), ADMIN-Konto sieht Abrufintervall+plattformweite Feeds ohne Postfach/Benachrichtigung, Zahnrad fuehrt in beiden Faellen nach Meine Quellen — kein Browser-Tool in dieser Sitzung verfuegbar | fixed | | 2026-08-12T10:02:49.291Z | 2026-09-07T07:50:56.910Z | | 9 | 17 | unrun-verify | apps/web/src/app/(portal)/modules/tender-radar/settings/page.tsx | | Browser-Gegenprobe Plan 17-03 Task 2: USER-Konto sieht keine Bedienelemente auf /settings (nur Hinweis+Verweis), ADMIN-Konto sieht Abrufintervall+plattformweite Feeds ohne Postfach/Benachrichtigung, Zahnrad fuehrt in beiden Faellen nach Meine Quellen — kein Browser-Tool in dieser Sitzung verfuegbar | fixed | | 2026-08-12T10:02:49.291Z | 2026-09-07T07:50:56.910Z |
| 10 | 15 | unmet-truth | apps/web/src/app/(portal)/modules/tender-radar/page.tsx | | PERM-04 greift nicht auf modul-eigenen Routen: der Zugriffs-Guard sitzt nur in modules/[category]/[moduleSlug]/page.tsx. Die vier fest verdrahteten Modulrouten (tender-radar, dkv-fleet, cert-manager, domaincheck) samt Unterseiten (z.B. tender-radar/my-sources) laufen daran vorbei und rendern fuer einen USER OHNE Modulfreigabe vollstaendig, inklusive bedienbarer Knoepfe. Im Browser gemessen am 2026-09-07 mit nutzer2 (keine Freigabe): /modules/procurement/tender-radar zeigt korrekt die 403-Seite, /modules/tender-radar und /modules/tender-radar/my-sources und /modules/dkv-fleet zeigen die volle Seite. Keine Datenpreisgabe - die API antwortet auf allen Endpunkten mit 403 - aber der Nutzer sieht Bedienelemente, die er nicht benutzen darf, und bekommt rohe englische Techniktexte statt einer verstaendlichen Meldung. Beleg: .planning/phases/17-eigene-ausschreibungs-quellen-je-nutzer/uat-2026-09-07/befund-modul-eigene-route-ohne-freigabe.png | open | | 2026-09-07T08:03:45.978Z | | | 10 | 15 | unmet-truth | apps/web/src/app/(portal)/modules/tender-radar/page.tsx | | PERM-04 greift nicht auf modul-eigenen Routen: der Zugriffs-Guard sitzt nur in modules/[category]/[moduleSlug]/page.tsx. Die vier fest verdrahteten Modulrouten (tender-radar, dkv-fleet, cert-manager, domaincheck) samt Unterseiten (z.B. tender-radar/my-sources) laufen daran vorbei und rendern fuer einen USER OHNE Modulfreigabe vollstaendig, inklusive bedienbarer Knoepfe. Im Browser gemessen am 2026-09-07 mit nutzer2 (keine Freigabe): /modules/procurement/tender-radar zeigt korrekt die 403-Seite, /modules/tender-radar und /modules/tender-radar/my-sources und /modules/dkv-fleet zeigen die volle Seite. Keine Datenpreisgabe - die API antwortet auf allen Endpunkten mit 403 - aber der Nutzer sieht Bedienelemente, die er nicht benutzen darf, und bekommt rohe englische Techniktexte statt einer verstaendlichen Meldung. Beleg: .planning/phases/17-eigene-ausschreibungs-quellen-je-nutzer/uat-2026-09-07/befund-modul-eigene-route-ohne-freigabe.png | fixed | | 2026-09-07T08:03:45.978Z | 2026-09-07T08:40:04.951Z |
| 11 | 13 | unmet-truth | apps/api/src/tenders/tender-fingerprint.ts | | Cross-Source-Dedup kollabiert die Mehrzahl echter Duplikate nicht: tenderFingerprint() haengt [buyerName, title, cpvDivisionKey, deadlineKey, valueBucket] zu einem String und hasht ihn. Die Scraper-Adapter liefern cpvDivisions immer leer, DOE dagegen meist gefuellt - dieselbe Ausschreibung ergibt aus beiden Quellen verschiedene Fingerabdruecke, die Fingerprint-Stufe greift also gerade dort nicht, wo sie greifen soll. Steht als offener Rest in 13-VERIFICATION.md (status gaps_found, 3/4 Wahrheiten), war aber bisher nicht im Ledger und damit unsichtbar. Die frueher vermutete Ursache (Normalizer-Defaults) ist mit 9881005 geschlossen und nicht gemeint. | open | | 2026-09-07T08:09:04.188Z | | | 11 | 13 | unmet-truth | apps/api/src/tenders/tender-fingerprint.ts | | Cross-Source-Dedup kollabiert die Mehrzahl echter Duplikate nicht: tenderFingerprint() haengt [buyerName, title, cpvDivisionKey, deadlineKey, valueBucket] zu einem String und hasht ihn. Die Scraper-Adapter liefern cpvDivisions immer leer, DOE dagegen meist gefuellt - dieselbe Ausschreibung ergibt aus beiden Quellen verschiedene Fingerabdruecke, die Fingerprint-Stufe greift also gerade dort nicht, wo sie greifen soll. Steht als offener Rest in 13-VERIFICATION.md (status gaps_found, 3/4 Wahrheiten), war aber bisher nicht im Ledger und damit unsichtbar. Die frueher vermutete Ursache (Normalizer-Defaults) ist mit 9881005 geschlossen und nicht gemeint. | open | | 2026-09-07T08:09:04.188Z | |
| 12 | 14 | unrun-verify | .planning/phases/14-rss-email-alert-ingestion-module-rollout/14-03-PLAN.md | | 14-03 Task 4 (checkpoint human-verify, gate blocking): echtes Portal-Alert-Postfach ueber den Exchange/EWS-Weg anbinden und eine echte Alarm-Mail ingestieren. Zu belegen sind (a) die Mail erzeugt eine mandantenprivate Ausschreibung, (b) ein anderer Mandant sieht sie nicht, (c) der EWS-Body-Abruf liefert nicht-leeren, nicht-verstuemmelten Inhalt gegen einen echten Exchange-Server. Der handgeschriebene NTLM/SOAP-Weg ist nur gegen gemocktes httpntlm.post geprueft, nie gegen einen echten Server. Braucht ein echtes Postfach - vom User am 2026-07-24 bewusst zurueckgestellt. Stand bisher nur in 14-VERIFICATION.md (status human_needed), nicht im Ledger. | open | | 2026-09-07T08:09:04.406Z | | | 12 | 14 | unrun-verify | .planning/phases/14-rss-email-alert-ingestion-module-rollout/14-03-PLAN.md | | 14-03 Task 4 (checkpoint human-verify, gate blocking): echtes Portal-Alert-Postfach ueber den Exchange/EWS-Weg anbinden und eine echte Alarm-Mail ingestieren. Zu belegen sind (a) die Mail erzeugt eine mandantenprivate Ausschreibung, (b) ein anderer Mandant sieht sie nicht, (c) der EWS-Body-Abruf liefert nicht-leeren, nicht-verstuemmelten Inhalt gegen einen echten Exchange-Server. Der handgeschriebene NTLM/SOAP-Weg ist nur gegen gemocktes httpntlm.post geprueft, nie gegen einen echten Server. Braucht ein echtes Postfach - vom User am 2026-07-24 bewusst zurueckgestellt. Stand bisher nur in 14-VERIFICATION.md (status human_needed), nicht im Ledger. | open | | 2026-09-07T08:09:04.406Z | |
@@ -145,10 +145,10 @@ last_updated: 2026-09-07T08:09:04.406Z
"file": "apps/web/src/app/(portal)/modules/tender-radar/page.tsx", "file": "apps/web/src/app/(portal)/modules/tender-radar/page.tsx",
"line": null, "line": null,
"description": "PERM-04 greift nicht auf modul-eigenen Routen: der Zugriffs-Guard sitzt nur in modules/[category]/[moduleSlug]/page.tsx. Die vier fest verdrahteten Modulrouten (tender-radar, dkv-fleet, cert-manager, domaincheck) samt Unterseiten (z.B. tender-radar/my-sources) laufen daran vorbei und rendern fuer einen USER OHNE Modulfreigabe vollstaendig, inklusive bedienbarer Knoepfe. Im Browser gemessen am 2026-09-07 mit nutzer2 (keine Freigabe): /modules/procurement/tender-radar zeigt korrekt die 403-Seite, /modules/tender-radar und /modules/tender-radar/my-sources und /modules/dkv-fleet zeigen die volle Seite. Keine Datenpreisgabe - die API antwortet auf allen Endpunkten mit 403 - aber der Nutzer sieht Bedienelemente, die er nicht benutzen darf, und bekommt rohe englische Techniktexte statt einer verstaendlichen Meldung. Beleg: .planning/phases/17-eigene-ausschreibungs-quellen-je-nutzer/uat-2026-09-07/befund-modul-eigene-route-ohne-freigabe.png", "description": "PERM-04 greift nicht auf modul-eigenen Routen: der Zugriffs-Guard sitzt nur in modules/[category]/[moduleSlug]/page.tsx. Die vier fest verdrahteten Modulrouten (tender-radar, dkv-fleet, cert-manager, domaincheck) samt Unterseiten (z.B. tender-radar/my-sources) laufen daran vorbei und rendern fuer einen USER OHNE Modulfreigabe vollstaendig, inklusive bedienbarer Knoepfe. Im Browser gemessen am 2026-09-07 mit nutzer2 (keine Freigabe): /modules/procurement/tender-radar zeigt korrekt die 403-Seite, /modules/tender-radar und /modules/tender-radar/my-sources und /modules/dkv-fleet zeigen die volle Seite. Keine Datenpreisgabe - die API antwortet auf allen Endpunkten mit 403 - aber der Nutzer sieht Bedienelemente, die er nicht benutzen darf, und bekommt rohe englische Techniktexte statt einer verstaendlichen Meldung. Beleg: .planning/phases/17-eigene-ausschreibungs-quellen-je-nutzer/uat-2026-09-07/befund-modul-eigene-route-ohne-freigabe.png",
"status": "open", "status": "fixed",
"reason": "", "reason": "",
"recorded_at": "2026-09-07T08:03:45.978Z", "recorded_at": "2026-09-07T08:03:45.978Z",
"resolved_at": null "resolved_at": "2026-09-07T08:40:04.951Z"
}, },
{ {
"id": 11, "id": 11,
@@ -4,7 +4,8 @@ kind: uat-nachtrag
date: 2026-09-07 date: 2026-09-07
windows_addressed: [1, 2, 3] windows_addressed: [1, 2, 3]
windows_opened: [10] windows_opened: [10]
result: 2 von 3 bestanden, 1 mit Befund windows_closed_later: [10]
result: 2 von 3 bestanden, 1 mit Befund — Befund am selben Tag behoben und gegengeprueft
--- ---
# Phase 15 — Browser-Gegenproben, nachgeholt am 2026-09-07 # Phase 15 — Browser-Gegenproben, nachgeholt am 2026-09-07
@@ -119,11 +120,36 @@ Diese laufen am Guard vorbei. Im Browser als `nutzer2` **ohne** Freigabe gemesse
Beleg: `uat-2026-09-07/befund-modul-eigene-route-ohne-freigabe.png` Beleg: `uat-2026-09-07/befund-modul-eigene-route-ohne-freigabe.png`
**Erwartete Behebung:** Die Zugriffsprüfung gehört in ein gemeinsames Layout über **Behoben am 2026-09-07** (Quick-Task `260907-e8k`, Commits `4a23e13`, `69b6418`).
allen Modulrouten (etwa `(portal)/modules/layout.tsx` mit Auflösung des Modul-Slugs Umgesetzt wurde nicht ein einzelnes Layout mit Pfadauflösung, sondern je ein `layout.tsx`
aus dem Pfad) statt in die einzelne Seitenkomponente der generischen Route. pro Modulverzeichnis mit fest eingetragenem Slug — ein Layout deckt in Next.js alle
verschachtelten Unterrouten automatisch mit ab, und der Slug steht damit explizit im Code
statt aus dem Pfad geraten zu werden. Das 403-Markup liegt jetzt einmal als gemeinsame
Komponente vor, die generische Route nutzt dieselbe. Ein Test liest das Modulverzeichnis
aus und verlangt für jedes nicht-dynamische Unterverzeichnis eine `layout.tsx`, damit ein
künftiges Modul die Lücke nicht erneut aufreißt.
### Gegenprobe im Browser nach dem Fix (2026-09-07)
Frisch gebautes Web-Image, echter Chrome, dieselben Konten:
| Konto | Adresse | Ergebnis |
|---|---|---|
| `admin` (SUPER_ADMIN) | `/modules/tender-radar`, `/modules/tender-radar/my-sources`, `/modules/dkv-fleet`, `/modules/procurement/tender-radar` | alle **unverändert offen** — die Sperre trifft niemanden zu viel |
| `nutzer1` (Freigabe über Gruppe) | `/modules/tender-radar/my-sources` | offen, alle drei Abschnitte da — Phase-17-Funktion unbeschädigt |
| `nutzer2` (keine Freigabe) | `/modules/tender-radar`, `/modules/tender-radar/my-sources`, `/modules/tender-radar/settings`, `/modules/dkv-fleet` | alle **gesperrt**, 403-Seite als Serverantwort |
| `nutzer2` auf `/modules/cert-manager` (dort **hat** er eine Freigabe) | | **offen** — die Gegenprobe gegen Überschießen |
Beleg: `uat-2026-09-07/w10-fix-my-sources-gesperrt.png`
**Messhinweis für spätere Prüfungen:** Ein erster Versuch, die Adressen per `fetch()` aus der
laufenden Seite heraus zu prüfen, meldete fälschlich *alle* Seiten als gesperrt — auch für den
Administrator. Der Aufruf führt die Sitzung nicht so mit, wie eine echte Navigation es tut. Die
Zahlen oben stammen ausschließlich aus echten Seitenaufrufen. Wer das nachprüft, sollte nicht
per `fetch` messen.
## Ergebnis ## Ergebnis
WINDOWS #1 und #2 sind geschlossen. #3 ist als Durchlauf erledigt; der dabei WINDOWS #1 und #2 sind geschlossen. #3 ist als Durchlauf erledigt. Der dabei gefundene
gefundene Defekt ist als #10 eigenständig erfasst und bleibt offen. Defekt wurde als #10 erfasst, am selben Tag behoben und im Browser gegengeprüft — er ist
damit ebenfalls geschlossen.
Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB