From 50b3a36f0c76cdec395aa714690101c66ea50b2c Mon Sep 17 00:00:00 2001 From: Schalli Date: Fri, 11 Sep 2026 09:17:06 +0200 Subject: [PATCH] docs: STATE-Zeile 260910-krx repariert (Shell hatte Backticks ausgewertet) --- .planning/STATE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.planning/STATE.md b/.planning/STATE.md index 578c92d..f46965e 100644 --- a/.planning/STATE.md +++ b/.planning/STATE.md @@ -383,7 +383,7 @@ None yet. | 260910-das | Mandantentrennung Etappe 2, Bereich user — Benutzerverwaltung, die schwerste Fehlerklasse des Vorhabens (Fremdzugriff hier ist Rechteausweitung ueber Mandantengrenzen, nicht blosse Sichtbarkeit). Alle 17 Zugriffe eingeordnet: Verwaltungswege gebunden, Eindeutigkeits- und Suchwege bewusst ungebunden, jede Entscheidung mit Begruendung am Ort. **Startsperre entschaerft — der schwerwiegendste Fund:** nach dem Scharfschalten haette eine FRISCHE Installation ihren ersten Administrator nicht anlegen koennen und die Anwendung waere gar nicht erst gestartet. Kette (Glied fuer Glied belegt): die Startpruefung liefert `null` — nicht weil der Admin fehlt, sondern weil ohne Mandantenkontext keine Zeile sichtbar ist — also wird angelegt, das laeuft in den plattformweit eindeutigen Anmeldenamen, und weil `seedAdmin()` ungekapselt in `onApplicationBootstrap` haengt, bricht der Start ab. Betroffen waere jede Installation mit gesetzten Admin-Umgebungswerten gewesen; auf dem bestehenden System nie aufgefallen, weil dort der Admin laengst existiert. Jetzt bindet die Erstanlage an den eine Anweisung zuvor angelegten Mandanten und faengt GENAU den Doppelanlage-Fall ab — jeder andere Fehler bricht den Start weiterhin ab (beide Haelften einzeln nachgewiesen). **Riegel repariert, der seit seiner Entstehung wirkungslos war:** die Sperre gegen das Loeschen des eigenen Kontos verglich gegen ein Feld, das der Sitzungsnachweis gar nicht traegt (`sub`; er traegt `id`, `username`, `role`, `tenantId`) — ein Administrator konnte sein eigenes Konto loeschen. Kein Mandantenproblem, gefunden weil dieser Durchlauf jede Zeile aufschlaegt. **Zwei Falschaussagen in eigenen Artefakten berichtigt:** der Kopfkommentar von `findByUsername` behauptete, sie muesse fuer den mandantenuebergreifenden Anmeldeweg ungebunden bleiben — der laeuft seit Etappe 1 ueber die SECURITY-DEFINER-Funktionen, und die Methode hat gemessen NULL Aufrufer; und die Klassifikationszeile der Erstanlage behauptete, es gebe strukturell keinen Mandanten zum Binden, obwohl er eine Anweisung vorher entsteht (Klasse auf `beides` korrigiert). **SUPER_ADMIN-Sicht** war nach dem Scharfschalten in JEDER heutigen Form kaputt (ungebunden null Zeilen, gebunden stille Funktionsminderung) — jetzt Schleife ueber alle Mandanten mit gebundenem Rumpf, neues Fundstellenpaar `(user.service.ts, tenant)`. **Steuerungsschicht hatte gar keine Tests** (7 der 17 Zugriffe plus die gesamte Rollenlogik) — `user.controller.spec.ts` neu. Plan-Pruefer fand einen Blocker: vier handgepflegte Dokumentstellen benannt, nur zwei abgesichert — also derselbe Fehler, den der Plan verhindern sollte; nachgebessert mit herleitenden statt fest verdrahteten Pruefungen, in vier Einzelmutationen falsifiziert. **Verifiziert 10/10** (810/810 Tests, Typpruefung sauber, 53/53 Live-Pruefungen; Selbstloesch-Riegel und Klassenverteilung vom Pruefer eigenhaendig nachgerechnet) | 2026-09-10 | b848ba6,888f660,3a9391d | [260910-das-mandantentrennung-etappe-2-bereich-user-](./quick/260910-das-mandantentrennung-etappe-2-bereich-user-/) | | 260910-exd | Mandantentrennung Etappe 2, Bereich module-registry — der Berechtigungs-Anfrageweg. `module.guard.ts` laeuft bei JEDER Modulanfrage und hat null eigene Datenbankzugriffe; seine Richtigkeit ist vollstaendig eine Funktion dessen, was dieser Bereich liefert. Endstand 7 ungebunden / 10 gebunden. **Eine Vorgabe des Auftrags war falsch und wurde widerlegt:** angeblich wuerde eine Bindung des Modulkatalogs ihn fuer jeden Mandanten unsichtbar machen — gemessen ueber alle 23 `ENABLE ROW LEVEL SECURITY`-Zeilen steht `Module` auf keiner, die Tabelle traegt gar keinen Zeilenschutz und kein `tenantId`. Eine Bindung waere heute WIRKUNGSLOS, nicht katastrophal; katastrophal wird sie erst, wenn Etappe 3 der Tabelle eine Regel gibt. Handlung unveraendert (Katalog bleibt ungebunden), aber Messung und Bedingung sind in Code und Dokument jetzt getrennt — eine richtige Handlung mit falscher Begruendung haelt nur, bis sich jemand auf die Begruendung verlaesst. **Die Kernfrage ehrlich beantwortet:** es gibt KEIN Signal, das 'wirklich keine Freigabe' von 'die Abfrage hat nichts gefunden' unterscheidet. Nach dem Scharfschalten saehe ein Unterlauf nicht wie ein Fehler aus, sondern wie 'du hast keine Module' — leere Seitenleiste, leerer Marktplatz, jeder Modulaufruf abgewiesen, fuer den Betroffenen nicht von einem absichtlichen Entzug zu unterscheiden. Dreifach festgehalten: im Text, als Testfall in `module.guard.spec.ts` (zwei Aufrufe, identische Meldung, gegeneinander gehalten) und als WINDOWS #23 mit konkreter Etappe-4-Vorabpruefung. **Erstmals eine Entlastung, die strukturell haelt:** die Kette unsichtbare Zeile -> falsches 'frei' -> 23505 kann hier nicht auftreten, weil die Eindeutigkeitsschluessel die Mandantenkennung fuehren — erster von sechs Bereichen, in dem sie abwesend statt umgangen ist; entsprechend wurde KEINE Absicherung eingebaut, die nichts absichert. **Wieder zwei Kopfkommentare mit Falschaussagen** (`isModuleActive` 'Used by ModuleGuard', `findActiveForTenant` als Marktplatz-Lieferant), beide Methoden mit null Aufrufern — berichtigt. `module-registry.service.ts` hatte trotz 11 der 17 Zugriffe und aller Schreibwege GAR KEINE Testdatei. Reihenfolge-Entlastung: der Dashboard-Filter wird mitgebunden, ohne dass eine `dashboard`-Datei angefasst wird. Zwei Abweichungen, beide vom eigenen Pruefgatter erzwungen und geprueft: eine Identitaets-Attrappe in `tender-scheduler.service.spec.ts` (zulaessig — jene Datei prueft Planer-Verhalten, die Bindung ist in `module-registry.service.spec.ts` mit zwei Klienten belegt) und eine Stand-Spalte, die eine Aufgabe frueher nachgezogen werden musste. **Verifiziert 9/9** (833/833 Tests, Typpruefung sauber, 66/66 Live-Pruefungen; Klassenverteilung und Summenzeile vom Pruefer eigenhaendig nachgerechnet). Eine Zahl in der Zusammenfassung (7 statt 6 neue Bindungsnachweise) vom Pruefer nachgezaehlt und berichtigt | 2026-09-10 | 7d45e2f,3df7268,9c0eefe | [260910-exd-mandantentrennung-etappe-2-bereich-modul](./quick/260910-exd-mandantentrennung-etappe-2-bereich-modul/) | | 260910-jab | **Die drei zu kurz greifenden Datenbankregeln geschlossen** — auf ausdrueckliche Anweisung des Users VORGEZOGEN, entgegen der geplanten Reihenfolge (urspruenglich nach Etappe 2, damit jeder Bereich gegen einen stabilen Regelstand misst; der User entschied anders, weil offene Loecher vergessen werden). Erster Durchlauf dieser Serie, der die DATENBANK aendert statt nur Anwendungscode — neue Migration `20260910120000_rls_widen_membership_grant_and_platform_read`. **T-JTS-02:** `GroupMembership` prueft jetzt BEIDE Seiten (Gruppe UND Benutzer gehoeren zum Mandanten) statt nur die Gruppenseite. **T-JTS-03:** `ModuleGrant` prueft zusaetzlich, dass die referenzierte Gruppe bzw. der referenzierte Benutzer zum selben Mandanten gehoert; `assertTargetBelongsToTenant` bleibt als zweite Verteidigungslinie bestehen. **WINDOWS #19:** `TenderRssFeedSource` bekommt VIER nach Befehl getrennte Regeln — Lesen schliesst plattformweite Zeilen ein, Einfuegen/Aendern/Loeschen verlangen weiter einen Mandanten (eine einzige lockere Regel haette jedem Mandanten erlaubt, gemeinsame Quellen zu aendern und zu loeschen, weil `USING` auch UPDATE und DELETE regelt). **Halbe Praemisse von #19 widerlegt:** bei `SearchProvider` gibt es gar keinen Codeweg, der eine mandantenlose Zeile erzeugt — Schreibweg verlangt den Mandanten, Vorgaben sind Konstanten (05-02); als widerlegte Annahme geschlossen, nicht als geloestes Problem, strenge Regel bleibt. **DREI Pruefungen schrieben die Loecher als erwartetes Verhalten fest** (meine eigene Suche fand nur zwei, der Planer die dritte) — alle drei UMGEDREHT statt geloescht, mit Verweis auf den urspruenglichen Befund: der ausfuehrbare Beleg, dass das Loch existierte, bleibt mit umgekehrtem Vorzeichen erhalten. **Die Reparatur erzeugte an einer Stelle selbst den Fehler, gegen den sie antritt:** `listForUser` haette nach der Regelaenderung die plattformweiten, aber nicht die persoenlichen Quellen geliefert — aus einer leeren Liste, die schreit, waere eine kurze geworden, die luegt; deshalb mitgebunden. **Messfalle abgefangen:** `extractPolicySql()` las nur die alten Migrationsverzeichnisse und haette nach der neuen Migration still die ABGELOESTE Regel weitergemessen. **Werkzeugfalle abgefangen:** der uebliche Aufrufweg haette beim Einspielen eine neue Prisma-Hauptversion nachgeladen; stattdessen die im Projekt festgelegte Fassung benutzt. Neuer offener Ledger-Eintrag #24: plattformweite Zeilen lassen sich unter der Anwendungsrolle weder anlegen noch entfernen — in alter wie neuer Regel. **Verifiziert 11/11 mit vier ZERSTOERENDEN Gegenproben** (jede Regel und die neue Bindung einzeln zurueckgedreht, jedes Mal schlug genau die zustaendige Pruefung fehl, danach byte-identisch wiederhergestellt). 839/839 Tests, Typpruefung sauber, 74/74 Live-Pruefungen; Regeltexte vom Orchestrator in der LAUFENDEN Datenbank gegengelesen | 2026-09-10 | f4f3115,6b23735,03fb3bf | [260910-jab-mandantentrennung-die-drei-zu-kurz-greif](./quick/260910-jab-mandantentrennung-die-drei-zu-kurz-greif/) | -| 260910-krx | Mandantentrennung Etappe 2, Bereich dashboard — 12 von 13 Zugriffen gebunden, der Modulkatalog bleibt bewusst ungebunden (Messung und Bedingung getrennt: heute ohne Zeilenschutz, daher wirkungslos, katastrophal erst wenn Etappe 3 eine Regel setzt). **Erster Bereich, in dem die Besitzpruefungen von Anfang an richtig waren:** dieselbe Bauform, die in ldap und dkv je eine Luecke riss (nachschlagen, dann loeschen), vergleicht hier dazwischen gegen die angemeldete Person — nichts zu reparieren, nur zu bestaetigen und durch Tests festzunageln. **Beweisvernichtungs-Schleife belegt, nicht vermutet (WINDOWS #25, offen):** nach dem Scharfschalten liefert bei unsichtbarer Zeile die Vorgabe, die Oberflaeche uebernimmt sie ohne Fehlerzustand, und das Verlassen des Bearbeitungsmodus schreibt AUTOMATISCH zurueck — der Nutzer ueberschreibt seine urspruengliche Anordnung selbst, ohne es zu merken; dazu haeufen sich Widget-Dubletten, weil es keine Eindeutigkeit ueber (userId, widgetType) gibt. Gehoert in die Etappe-4-Vorabpruefung, nicht in diesen Umbau. Suchleiste: der Rueckfallzweig feuert nie leer, weil drei Vorgaben immer vorangestellt sind — die eigenen Suchmaschinen verschwinden schlicht. ist plattformweit eindeutig ohne Mandantenanteil (Familie WINDOWS #22). **Der Verifizierer fand eine Luecke der bekannten Art:** die Behauptung, ein gebundener Konfliktschreibvorgang werfe (nicht den P2002-Fall von tenders/user), stuetzte sich auf eine NICHT committete Ad-hoc-Messung — Pruefung 5 mass nur Roh-SQL, kein Test uebte den catch-Zweig. Nachgereicht (6e71206): Messung ueber den GENERIERTEN Client (Konstruktorname geprueft), dabei die Wegwerf-Tabelle korrigiert, der Roh-SQL nie aufgefallen war (createdAt/updatedAt fehlten, der echte Client scheiterte sofort mit P2022); zwei Tests fuer den catch-Zweig, durch Rueckbau falsifiziert. Klassifikation: fremde Datei mit ungenauem Kopfkommentar bewusst NICHT angefasst, Ungenauigkeit in (w5) festgehalten. **Verifiziert 10/11, Luecke behoben** (860/860 Tests, Typpruefung sauber, 88/88 Live-Pruefungen; alle drei Falsifizierungsnachweise vom Pruefer eigenhaendig reproduziert) | 2026-09-11 | 6744918,e0ce594,67b5024,6e71206 | [260910-krx-mandantentrennung-etappe-2-bereich-dashb](./quick/260910-krx-mandantentrennung-etappe-2-bereich-dashb/) | +| 260910-krx | Mandantentrennung Etappe 2, Bereich dashboard — 12 von 13 Zugriffen gebunden, der Modulkatalog bleibt bewusst ungebunden (Messung und Bedingung getrennt: heute ohne Zeilenschutz, daher wirkungslos, katastrophal erst wenn Etappe 3 eine Regel setzt). **Erster Bereich, in dem die Besitzpruefungen von Anfang an richtig waren:** dieselbe Bauform, die in ldap und dkv je eine Luecke riss (nachschlagen, dann loeschen), vergleicht hier dazwischen gegen die angemeldete Person — nichts zu reparieren, nur zu bestaetigen und durch Tests festzunageln. **Beweisvernichtungs-Schleife belegt, nicht vermutet (WINDOWS #25, offen):** nach dem Scharfschalten liefert `getLayout` bei unsichtbarer Zeile die Vorgabe, die Oberflaeche uebernimmt sie ohne Fehlerzustand, und das Verlassen des Bearbeitungsmodus schreibt AUTOMATISCH zurueck — der Nutzer ueberschreibt seine urspruengliche Anordnung selbst, ohne es zu merken; dazu haeufen sich Widget-Dubletten, weil es keine Eindeutigkeit ueber (userId, widgetType) gibt. Gehoert in die Etappe-4-Vorabpruefung, nicht in diesen Umbau. Suchleiste: der Rueckfallzweig feuert nie leer, weil drei Vorgaben immer vorangestellt sind — die eigenen Suchmaschinen verschwinden schlicht. `DashboardLayout.userId` ist plattformweit eindeutig ohne Mandantenanteil (Familie WINDOWS #22). **Der Verifizierer fand eine Luecke der bekannten Art:** die Behauptung, ein gebundener Konfliktschreibvorgang werfe `PrismaClientUnknownRequestError` (nicht den P2002-Fall von tenders/user), stuetzte sich auf eine NICHT committete Ad-hoc-Messung — Pruefung 5 mass nur Roh-SQL, kein Test uebte den catch-Zweig. Nachgereicht (6e71206): Messung ueber den GENERIERTEN Client (Konstruktorname geprueft), dabei die Wegwerf-Tabelle korrigiert, der Roh-SQL nie aufgefallen war (createdAt/updatedAt fehlten, der echte Client scheiterte sofort mit P2022); zwei Tests fuer den catch-Zweig, durch Rueckbau falsifiziert. Klassifikation: fremde Datei `groups.service.ts` mit ungenauem Kopfkommentar bewusst NICHT angefasst, Ungenauigkeit in (w5) festgehalten. **Verifiziert 10/11, Luecke behoben** (860/860 Tests, Typpruefung sauber, 88/88 Live-Pruefungen; alle drei Falsifizierungsnachweise vom Pruefer eigenhaendig reproduziert) | 2026-09-11 | 6744918,e0ce594,67b5024,6e71206 | [260910-krx-mandantentrennung-etappe-2-bereich-dashb](./quick/260910-krx-mandantentrennung-etappe-2-bereich-dashb/) | | 260909-eor | Etappe 1 der Mandantentrennung: Anmeldeweg mandantenfaehig gemacht und alle Zugriffe klassifiziert. **Kernfund (#20):** `forTenant()` setzte den Mandantenkontext per set_config auf der Transaktionsverbindung, dispatchte die Abfrage aber ueber den aeusseren Client — empirisch reproduziert (set_config auf Backend-PID 254999, Abfrage auf 255000, Kontext dort NULL). Die Trennung hat damit nie funktioniert, auch nicht an den Stellen, die sie scheinbar nutzten; nach dem Scharfschalten haetten diese Abfragen NULL Zeilen geliefert, was der LDAP-Loeschzweig als 'Gruppe im Verzeichnis verschwunden' gedeutet und geloescht haette. Behoben und live nachgewiesen. Der Anmeldeweg bekam drei SECURITY-DEFINER-Funktionen als schmale Ausnahme (feste Spaltenliste, Gleichheitsbedingung, LIMIT 1) — eine Policy haette nicht gereicht, weil sie zwangslaeufig die ganze Tabelle freigibt. Browser-Gegenprobe lokal bestanden: Anmeldung laedt das Portal, falsches Kennwort verraet weiterhin nicht welches Feld, Kennwort-vergessen laeuft durch (der einzige Protokollfehler war ein lokal fehlender Mailserver, also NACH dem Datenbankzugriff). Klassifikation aller 227 Zugriffe in 59 Einheiten, maschinell gegen Abdriften abgesichert: 31 muessen mandantengebunden werden, 9 teilweise, 16 betreffen keine mandantengebundene Tabelle, 3 bleiben bewusst uebergreifend. 701 Tests gruen | 2026-09-09 | da0ac04 | [260909-eor-anmeldeweg-mandantenfaehig-machen-und-al](./quick/260909-eor-anmeldeweg-mandantenfaehig-machen-und-al/) | | 260910-jab | Die drei zu kurz greifenden Datenbankregeln geschlossen — T-JTS-02, T-JTS-03, WINDOWS #19 (bewusste Reihenfolge-Abweichung, vorgezogen auf Nutzerwunsch, statt wie geplant nach Etappe 2). Neue, handgeschriebene, lokal angewandte Migration `20260910120000_rls_widen_membership_grant_and_platform_read`: `GroupMembership` prueft jetzt beide Seiten der Beziehung (Gruppe UND Benutzer), `ModuleGrant` prueft zusaetzlich beide moeglichen Ziele mit Leer-Zulassung (D-04), `TenderRssFeedSource` bekommt vier nach Befehl getrennte Regeln (Lesen schliesst plattformweite Zeilen ein, Schreiben verlangt weiterhin einen Mandanten — die Trennung ist noetig, weil ein einzelner USING-Ausdruck sonst auch UPDATE/DELETE mitregelt). `SearchProvider` bewusst NICHT angefasst: die WINDOWS-#19-Praemisse ist fuer dieses Modell widerlegt (kein Codeweg erzeugt eine mandantenlose Zeile). Drei loch-behauptende Pruefungen im Wegwerf-Werkzeug UMGEKEHRT statt geloescht (66→74 Pruefungen), mit Verweis auf die alten Pruefungsnamen und Befundkennungen im Meldetext. Genau EIN Anwendungspfad musste mitgebunden werden (`TenderRssFeedSourceService.listForUser`) — sonst haette die Reparatur ihn still von 'liefert nach dem Scharfschalten nichts' auf 'liefert nur die plattformweiten Zeilen, taeuscht Vollstaendigkeit vor' verschlechtert; Falsifizierungsnachweis gefuehrt (Bindung zurueckgenommen, genau ein Test rot, zurueckgesetzt). WINDOWS #19 geschlossen mit Beleg, WINDOWS #24 neu angelegt (Verwaltungsweg fuer plattformweite Zeilen unter der Anwendungsrolle fehlt weiterhin — verschwindet nicht mit #19). Aktenstand kohaerent: Klassifikation, Kritikschrift (neuer Abschnitt "Regelschluss T-JTS-02, T-JTS-03 und WINDOWS #19" mit Signaltabelle beider Fehlerrichtungen je Regel), Betriebsanleitung, WINDOWS.md — fuenf ueberholte Bestandsstellen mit Nachtraegen versehen, alte Messprotokolle bleiben woertlich stehen. Selbst gemessen statt uebernommen: Baseline 833/56 Tests, 66/66 Live-Pruefungen; Endstand 839/56, 74/74; keine zweite Sitzungsvariable fuer den Benutzer gefunden (nur `app.current_tenant`). Rule-1-Fix: implizites `any` in `tenders.controller.ts` nach der Bindung behoben. `npx prisma` versuchte ungefragt Prisma 8 herunterzuladen — abgebrochen, lokale gepinnte 6.19.3 verwendet | 2026-09-10 | f4f3115,6b23735,03fb3bf | [260910-jab-mandantentrennung-die-drei-zu-kurz-greif](./quick/260910-jab-mandantentrennung-die-drei-zu-kurz-greif/) |