279 lines
21 KiB
Markdown
279 lines
21 KiB
Markdown
# Changelog
|
||
|
||
Alle nennenswerten Änderungen an Laufzettel werden in dieser Datei dokumentiert.
|
||
|
||
Das Format basiert auf [Keep a Changelog](https://keepachangelog.com/de/1.1.0/),
|
||
und dieses Projekt folgt [Semantic Versioning](https://semver.org/lang/de/).
|
||
|
||
## [Unveröffentlicht]
|
||
|
||
### Hinzugefügt
|
||
|
||
- Projektgerüst: Next 16 mit App Router und TypeScript strict, Tailwind 4, Vitest 5,
|
||
Playwright 1.63, ESLint flat config, Prettier, husky mit lint-staged und commitlint (#005)
|
||
- Gestaltung: Design-Token als CSS-Variablen, selbst gehostete Schriften, Wortmarke und
|
||
Bildmarke `[ ✓ ]`, Versionsanzeige unten links (#005)
|
||
- Betriebsstand mit Docker Compose: die Datenbank ist von außen nicht erreichbar — kein
|
||
veröffentlichter Port und ein Netz ohne Gateway; Migrationen laufen beim Start in einem
|
||
eigenen Einmal-Dienst, der Seed bleibt ein bewusster Handgriff (#005)
|
||
- Healthcheck `GET /api/gesundheit` und Sicherheitskopfzeilen samt CSP-Nonce je Anfrage (#005)
|
||
- shadcn/ui eingerichtet: sein Variablen-Vertrag wird aus den Laufzettel-Token gespeist, damit
|
||
kopierte Bauteile ohne Nacharbeit passen (#005)
|
||
- `pnpm pruefe:doku` hält Dokumentation und Code zusammen: Version im Changelog, Issue-Dateien
|
||
gegen ihre Übersicht, keine Verweise auf fehlende Dateien, keine fehlenden Bilder (#005)
|
||
- `pnpm docs:screenshots` erzeugt Screenshots reproduzierbar und prüft dabei gleich, dass am
|
||
Handy nicht horizontal gescrollt wird (#005)
|
||
- Issues, Labels und Meilensteine für alle vier Phasen im Gitea-Tracker (#001–#019)
|
||
- Vollständiges Datenmodell in deutscher Benennung: 20 Tabellen, 9 Aufzählungen, erste
|
||
Migration, idempotenter Seed für Betriebsmodus, eigene Organisation und Administrator (#006)
|
||
- Erzeugung der `tagCode`s für die QR-Aufkleber, mit Vergabebuch, aus dem nie gelöscht wird —
|
||
ein Code kommt auch nach dem Löschen eines Geräts nicht zurück (#006)
|
||
- Verschlüsselung von Geheimnissen mit AES-256-GCM aus `APP_SECRET`, für das LDAP-Bind-Passwort
|
||
und später die Zugangsdaten der Connectoren (#006)
|
||
- Anmeldung über einen generischen OIDC-Anbieter mit Discovery, PKCE, `state` und `nonce`;
|
||
unbekannte Benutzer entstehen beim ersten Login, die Rolle kommt bei jeder Anmeldung neu aus
|
||
den Gruppen (#007)
|
||
- Lokale Anmeldung mit E-Mail und Passwort als Notfallzugang, nur bei `AUTH_LOCAL_ENABLED=true`
|
||
(#007)
|
||
- Rechte in einer Tabelle mit vier Rollen; geprüft ausschließlich serverseitig, Rolle und
|
||
Aktiv-Status pro Anfrage aus der Datenbank (#007)
|
||
- Benutzerverwaltung für Administratoren: Rolle setzen, Konto abschalten, lokales Konto
|
||
anlegen (#007)
|
||
- Navigation zeigt nur, was die eigene Rolle darf (#007)
|
||
- Betriebsmodus **Intern** und **Dienstleistung**, umschaltbar ohne Neustart. Im Modus Intern
|
||
erscheint die eigene Organisation nirgends; der Wechsel nimmt alle Geräte, Personen,
|
||
Abteilungen und Läufe mit, weil jede Zeile ohnehin schon eine Kunden-Zuordnung trägt (#008)
|
||
- Bestätigungsdialog für den Moduswechsel, der die Folgen aus derselben Prüfung zeigt, die der
|
||
Wechsel danach durchsetzt (#008)
|
||
- Kundenverwaltung im Modus Dienstleistung: anlegen, bearbeiten, archivieren statt löschen (#008)
|
||
- Admin → Einstellungen: Betriebsmodus, Name der eigenen Organisation, globale Namensregeln,
|
||
Sperr-OU und die Anzeige der Adresse, die in den QR-Codes steckt (#008)
|
||
- Navigation und Beschriftungen folgen dem Betriebsmodus — ein Codepfad, nur ein- und
|
||
ausgeblendete Einträge (#008)
|
||
- Versionierte Vorlagen: „Bearbeiten“ erzeugt eine tiefe Kopie der zuletzt veröffentlichten
|
||
Version als Entwurf, je Vorlage gibt es höchstens einen. Veröffentlichen hält Zeitpunkt,
|
||
Urheber und Änderungsnotiz fest (#009)
|
||
- Vorlagen duplizieren und archivieren statt löschen (#009)
|
||
- JSON-Export und -Import für Vorlagen, Format dokumentiert in `docs/vorlagen-format.md` (#009)
|
||
- Zwei Redakteure am selben Entwurf treten sich nicht mehr auf die Füße: wer auf einem überholten
|
||
Stand speichert, wird abgewiesen statt die Arbeit des anderen spurlos zu überschreiben (#009)
|
||
- Vorlagenliste mit Suche, Filter nach Kategorie und Schlagwort und dem Kennzeichen
|
||
„Entwurf vorhanden“; eine Vorlage lässt sich anlegen, duplizieren, archivieren und als JSON
|
||
ein- und ausspielen (#010)
|
||
- Vorlagen-Editor: Abschnitte, Schritte und Variablen anlegen, bearbeiten, löschen und sortieren
|
||
— mit dem Finger, der Maus, der Tastatur oder zwei Knöpfen an jeder Zeile (#010)
|
||
- Typabhängige Felder je Schritt: Auswahloptionen, Zahlenbereich mit Einheit, mehrzeiliger Text,
|
||
Shell und Befehlstext; Hilfetexte als Markdown, dazu ein Doku-Link (#010)
|
||
- Warnung im Editor, wenn ein Platzhalter zu keiner Variablen und zu keinem eingebauten Wert
|
||
gehört — sie blockiert nichts, sie zeigt den Tippfehler, bevor der Techniker ihn im Lauf findet
|
||
(#010)
|
||
- Vorschau der Vorlage mit Beispielwerten, so wie ein Lauf sie zeigen wird (#010)
|
||
- Versionsgeschichte je Vorlage: wer wann mit welcher Notiz veröffentlicht hat und wie viele Läufe
|
||
an einer Version hängen (#010)
|
||
- Mitarbeiterliste mit Suche über Anzeigename, Mail, UPN und sAMAccountName, Filter nach Abteilung;
|
||
standardmäßig nur aktive Personen, mit Umschalter auch deaktivierte (#011)
|
||
- Mitarbeiterseite mit Stammdaten, zugeordneten Geräten und Platz für die Laufhistorie; Personen
|
||
werden deaktiviert statt gelöscht (#011)
|
||
- Abteilungen unter Admin: Ziel-OU, Standardgruppen und Mail-Domain — daraus entstehen später die
|
||
Befehle, die ein Konto anlegen. Abteilungsnamen, die bei Personen vorkommen, aber nicht gepflegt
|
||
sind, werden eigens ausgewiesen (#011)
|
||
- Geräteliste mit Suche über Hostname, Bezeichnung, Seriennummer und Tag-Code, Filter nach Typ;
|
||
Geräte anlegen, bearbeiten, archivieren (#011)
|
||
- CSV-Import für Geräte: je Zeile ein Ergebnis, eine fehlerhafte Zeile bricht den Import nicht ab,
|
||
sondern wird mit Zeilennummer und Grund gemeldet. Der Zerleger kommt mit Semikolon, BOM, CRLF,
|
||
Anführungszeichen und Zeilenumbrüchen im Wert zurecht (#011)
|
||
- Die Seitenleiste führt Personen und Geräte unter einem Eintrag; ein Umschalter wechselt zwischen
|
||
beiden Listen (#011)
|
||
- Platzhalter werden aufgelöst: eingebaute Werte aus Gerät, Lauf, Mitarbeiter und Abteilung, dazu
|
||
die Variablen der Vorlage. Ein unbekannter Platzhalter bleibt sichtbar stehen, statt still zu
|
||
verschwinden (#012)
|
||
- `{{ou}}` einer Person aus dem Verzeichnis ist der Eltern-Container ihres DN — genau der Pfad, den
|
||
ein `New-ADUser -Path` braucht (#012)
|
||
- Namensregeln für `upn`, `sam`, `mail` und `hostname` mit Transliteration, `{v}`, `{nnn}` und
|
||
`{kundenkuerzel}`; im Modus Dienstleistung überlagern Kundenregeln die globalen Feld für Feld
|
||
(#012)
|
||
- „Alle Befehle als Skript kopieren“ je Abschnitt: die Befehle in Reihenfolge, je mit einer
|
||
Kommentarzeile darüber und dem Zeilenumbruch der jeweiligen Shell (#012)
|
||
- Läufe: anlegen — auch als `offen` ohne Start, das ist die Zuweisung —, abarbeiten, abschließen
|
||
und archivieren. Ein Lauf wird erst `in Arbeit`, wenn ihn jemand wirklich öffnet (#013)
|
||
- Abarbeitungsansicht: nummerierte Abschnitte, Fortschrittsbalken, je Schritt Zustand, Wert,
|
||
Notiz, Kommentare und „wer wann“; jeder Schritt speichert einzeln, damit ein verlorener Klick
|
||
nicht zwei Stunden Arbeit kostet (#013)
|
||
- Die Ansicht frischt sich alle zehn Sekunden auf und pausiert, solange der Tab im Hintergrund
|
||
liegt — zwei Techniker an einem Onboarding sehen die Arbeit des anderen (#013)
|
||
- Umschalter „Kompakt / Ausführlich“: beim ersten Mal sind die Hilfetexte der eigentliche Wert,
|
||
beim dritten Mal stehen sie im Weg (#013)
|
||
- Befehlsschritte zeigen den fertigen Befehl mit eingesetzten Werten und einem Kopier-Knopf; ein
|
||
unaufgelöster Platzhalter wird angezeigt, statt stillschweigend mitkopiert zu werden (#013)
|
||
- „Abschnitt trifft nicht zu“ setzt alle Schritte eines Abschnitts mit einer Begründung auf
|
||
`nicht zutreffend` — für die Konto-Abschnitte eines Onboardings ohne eigenes AD (#013)
|
||
- Kommentare am Lauf und am einzelnen Schritt (#013)
|
||
- Ein Lauf mit Freitextnamen lässt sich nachträglich mit einem Konto aus dem Verzeichnis
|
||
verknüpfen: beim Onboarding gibt es die Person dort noch nicht (#013)
|
||
- Start-Dialog mit Vorbelegung aus der Adresse, Laufliste mit Suche nach Titel, Ticket, Hostname
|
||
und Person sowie Filter nach Status und eigener Zuweisung (#013)
|
||
- Der Start-Dialog schlägt `upn`, `sam` und `mail` nach den Namensregeln vor, sobald die Vorlage
|
||
solche Variablen hat; ausgefüllte Felder bleiben stehen (#013)
|
||
- Abschnitte klappen zu, sobald in ihnen nichts mehr zu tun ist — wer einen wieder aufklappt,
|
||
behält ihn offen, auch über das Speichern hinweg (#013)
|
||
|
||
- QR-Aufkleber: Stapel vorgedruckter Tags, Etikettendruck als Einzeletikett (62 × 29 mm) und als
|
||
A4-Bogen (3 × 8 à 70 × 37 mm), je mit QR, lesbarem Code, Hostname und Besitzer (#014)
|
||
- `/t/<code>` als Einstieg vom Aufkleber: registriertes Gerät → Geräteseite, vorgedruckter Tag →
|
||
Registrierformular, unbekannter Code → Hinweis mit Weg zur Suche (#014)
|
||
- Geräteseite mit Kopf, „Zugewiesen“, Schnellstart aus den Gerätetyp-Vorgaben, „Vorlage zuweisen“
|
||
und Historie — am Handy bedienbar, weil sie dort benutzt wird (#014)
|
||
- „Scannen“ mit der BarcodeDetector-API des Browsers, wo es sie gibt, sonst mit WebAssembly; wo
|
||
keine Kamera läuft, steht ein Feld für den abgetippten Code (#014)
|
||
- Der Tag-Code in der Geräteliste und in der Tag-Liste führt dorthin, wo auch der Scan landet (#014)
|
||
|
||
- Übersicht: überfällige Läufe, die eigenen Zuweisungen, zuletzt Bearbeitetes und ein Schnellstart
|
||
aus den Vorlagen, aus denen im Haus am häufigsten Läufe entstehen (#015)
|
||
- Archiv mit Volltextsuche über Titel, Notizen, erfasste Werte und Kommentare in einem gemeinsamen
|
||
Lesemodell; die Trefferliste zeigt, **wo** der Begriff steht, und hebt ihn hervor (#015)
|
||
- Filter im Archiv nach Vorlage, Person, Abteilung, Gerät, Zeitraum und Bearbeiter — im Modus
|
||
Dienstleistung zusätzlich nach Kunde (#015)
|
||
- Druckansicht eines Laufs: hell, ohne Navigation, auf A4, mit allen Schritten, Werten, Notizen,
|
||
Namen und Zeitstempeln. Sie ersetzt im MVP den PDF-Export (#015)
|
||
|
||
- Verzeichnis-Abgleich über LDAP: Quelle anlegen, Verbindung testen, nach Zeitplan oder auf Knopfdruck
|
||
abgleichen. Wer im Verzeichnis verschwindet oder deaktiviert wird, wird hier inaktiv — gelöscht wird
|
||
nie, sonst verlöre die Historie ihre Namen (#016)
|
||
- „Verbindung testen“ zeigt die ersten Einträge **mit den gemappten Feldern** und schreibt nichts: erst
|
||
daran sieht ein Administrator, ob die Zuordnung stimmt (#016)
|
||
- Der Zeitplan läuft im selben Prozess wie die Anwendung, sieht jede Minute nach, welche Quelle fällig
|
||
ist, und verlässt sich auf eine Sperre in der Datenbank — zwei Instanzen kommen sich nicht in die
|
||
Quere (#016)
|
||
- Personen aus einer CSV-Datei einlesen: je Zeile ein Ergebnis, eine fehlerhafte Zeile bricht den
|
||
Import nicht ab. Eine leere Zelle löscht nichts, und wer schon aus dem Abgleich stammt, wird nicht
|
||
überschrieben (#016)
|
||
- Abteilungsvorschläge aus den Verzeichnis-Werten: ein Klick macht daraus eine gepflegte Abteilung
|
||
(#016)
|
||
- Die Attributzuordnung ist in der Oberfläche bearbeitbar: zehn Felder mit den AD-Vorgaben, damit ein
|
||
OpenLDAP nicht in der Datenbank nachgepflegt werden muss (#016)
|
||
- Abgleich-Log je Quelle: die letzten zehn Läufe mit gelesen, angelegt, übernommen, aktualisiert,
|
||
deaktiviert und übersprungen — und wer sie angestoßen hat, Mensch oder Zeitplan (#016)
|
||
- Wer schon von Hand angelegt wurde und dann im Verzeichnis auftaucht, wird **übernommen** statt
|
||
verdoppelt: dieselbe Zeile behält ihre Läufe und Geräte (#016)
|
||
- Ein hinterlegtes CA-Zertifikat ist als vorhanden erkennbar und lässt sich entfernen; der
|
||
Zertifikatstext selbst kommt nie zurück in die Oberfläche (#016)
|
||
|
||
### Sicherheit
|
||
|
||
- Der Compose-Stand bricht ab, wenn `APP_SECRET`, `POSTGRES_PASSWORD` oder `APP_URL` fehlen,
|
||
statt mit Standardwerten zu starten (#005)
|
||
- Die Mandantengrenze steht als zusammengesetzter Fremdschlüssel in der Datenbank: ein Lauf kann
|
||
strukturell kein Gerät, keine Person und keine Abteilung eines fremden Kunden wählen (#006)
|
||
- Ein Bind-Passwort ohne Versionspräfix wird von der Datenbank abgewiesen, ein versehentlich im
|
||
Klartext geschriebenes fällt damit sofort auf (#006)
|
||
- Ein Lauf nimmt seine Schrittergebnisse und Kommentare beim Löschen nicht mehr mit, und ein
|
||
Protokolleintrag kann seinen Urheber nicht mehr verlieren (#006)
|
||
- Das Rücksprungziel nach der Anmeldung wird aufgelöst und gegen die eigene Herkunft geprüft,
|
||
statt nur Präfixe zu vergleichen — `/<TAB>/fremd.example` wäre sonst eine offene Weiterleitung
|
||
gewesen (#007)
|
||
- Alle Umleitungen gehen über `APP_URL` statt über die Herkunft der Anfrage; hinter einem Reverse
|
||
Proxy zeigten sie sonst auf den internen Host (#007)
|
||
- Eine Anmeldung über den Anbieter verknüpft nur mit einem bestehenden Konto, wenn die Adresse
|
||
bestätigt ist (#007)
|
||
- Ohne eingerichtete `OIDC_GROUP_*`-Zuordnung bleibt die Rolle unangetastet, statt jeden auf
|
||
`LESER` herabzustufen (#007)
|
||
- Der letzte aktive Administrator kann sich weder herabstufen noch abschalten (#007)
|
||
- Beim Abschalten eines Kontos werden laufende Sitzungen sofort ungültig (#007)
|
||
- Im Modus Intern wird eine vom Client mitgeschickte Kunden-Zuordnung verworfen, nicht bloß
|
||
abgelehnt — es gibt in diesem Modus keine Kundenwahl (#008)
|
||
- Der Rückweg nach Intern wird abgelehnt, solange mehr als ein nicht archivierter Kunde
|
||
existiert (#008)
|
||
- Die eigene Organisation lässt sich nicht archivieren (#008)
|
||
- Eine veröffentlichte Vorlagen-Version ist unveränderlich: jeder Schreibversuch wird abgewiesen,
|
||
und ein bestehender Lauf zeigt auch nach neuen Veröffentlichungen genau die Schritte, mit denen
|
||
er gestartet wurde (#009)
|
||
- Die Unveränderlichkeit setzt zusätzlich die Datenbank durch, damit auch Migrationen, `psql` und
|
||
spätere Connectoren nicht daran vorbeischreiben können; der Rückweg nach Entwurf ist versperrt
|
||
(#009)
|
||
- Vorlagen eines fremden Kunden bleiben auch bei Suche und Filtern verborgen, und Historie wie
|
||
Aufbau einer Version geben nichts heraus, was der Benutzer nicht sehen darf (#009)
|
||
- Der Doku-Link eines Schritts nimmt nur `http` und `https` an; über eine importierte Datei wäre
|
||
ein `javascript:`-Link sonst fremder Code im Browser des Technikers (#009)
|
||
- Hilfetexte werden als Markdown ohne rohes HTML gerendert — ein Skript im Hilfetext einer
|
||
eingespielten Vorlage bleibt sichtbarer Text (#010)
|
||
- Der Doku-Link eines Schritts wird auch in der Vorschau nur dann verlinkt, wenn er `http` oder
|
||
`https` ist — dort hat ihn das Schema noch nicht gesehen (#010)
|
||
- Die Content-Security-Policy lockert `unsafe-eval` und WebSocket-Verbindungen **nur** im
|
||
Entwicklungsmodus; ein Test prüft die Entscheidung im Proxy selbst und nicht bloß die Funktion
|
||
darunter (#010)
|
||
- Eine abgelaufene Anmeldung beendet den Vorgang mit einer Meldung, statt die Seite auszuhängen —
|
||
im Editor wäre sonst jede ungespeicherte Arbeit verloren gewesen (#010)
|
||
- Eine archivierte Kundenzuordnung bleibt beim Speichern der Kopfdaten erhalten, statt sich
|
||
stillschweigend in „für alle Kunden“ zu verwandeln (#010)
|
||
- Die Stammdaten einer Person aus dem Verzeichnis lassen sich nicht von Hand überschreiben — der
|
||
nächste Abgleich würde die Änderung ohnehin zurückdrehen, und ein Wert, der zwischen zwei Läufen
|
||
hin- und herspringt, ist schlimmer als ein falscher. Deaktivieren bleibt möglich (#011)
|
||
- Ein Gerät kann nur einer Person desselben Kunden gehören; der Dienst sagt es verständlich, bevor
|
||
der zusammengesetzte Fremdschlüssel zuschlägt (#011)
|
||
- Ein Gerät, an dem Läufe hängen, lässt sich nicht löschen, nur archivieren (#011)
|
||
- Der Tag-Code entsteht beim Anlegen, steht sofort im Vergabebuch und lässt sich nie ändern — beides
|
||
in einer Transaktion, damit kein Code ohne Eintrag entsteht (#011)
|
||
- Werte werden für die jeweilige Shell maskiert, bevor sie in einen Befehl kommen: PowerShell
|
||
verdoppelt `"` und Backtick und entschärft `$`, Bash setzt einfache Anführungszeichen. Für Cmd
|
||
wird ein Wert mit `"` oder Zeilenumbruch **abgelehnt** statt unsicher maskiert — dort gibt es
|
||
keine Regel, die in jedem Fall stimmt (#012)
|
||
- `{{generiertes_passwort}}` entsteht bei jeder Anzeige neu, besteht aus 20 Zeichen ohne
|
||
verwechselbare Buchstaben und wird nirgends gespeichert; in der Druckansicht steht
|
||
`[Passwort – nicht gespeichert]` (#012)
|
||
- Ein eingesetzter Wert wird nicht doppelt maskiert: React maskiert Textknoten selbst, und ein Test
|
||
am gerenderten HTML hält fest, dass ein `<script>` im Namen wirklich als Text ankommt (#012)
|
||
- Der Archiv-Schreibschutz sitzt an genau einer Stelle und wird vor jeder Änderung an Kopfdaten,
|
||
Schrittergebnis und Kommentar gerufen; ein abgeschlossener Lauf bleibt änderbar, ein archivierter
|
||
nicht, und zurückholen darf nur ein Administrator (#013)
|
||
- Ein Abschluss nimmt sich selbst zurück, sobald eine spätere Änderung einen Pflichtschritt wieder
|
||
offen lässt — „abgeschlossen“ soll nicht lügen (#013)
|
||
- `nicht zutreffend` und `fehlgeschlagen` verlangen eine Begründung; das Feld erscheint, bevor
|
||
gespeichert wird, statt den Benutzer in eine Absage laufen zu lassen (#013)
|
||
- Der Zustands-Endpunkt für die Aktualisierung prüft das Leserecht selbst, liefert einen fremden
|
||
Lauf als „nicht gefunden“ und **keine Befehle** — sonst entstünde bei jedem Abruf ein neues
|
||
generiertes Passwort (#013)
|
||
- In einem Lauf steht **ein** generiertes Passwort, nicht je Vorkommen ein anderes: der Befehl, der
|
||
das Konto anlegt, und die Zeile, die das Passwort mitteilt, meinen dasselbe. Vorher hätte das
|
||
Konto A bekommen und der Benutzer B erfahren — und A wäre unwiederbringlich gewesen (#013)
|
||
- Die Aktualisierung lädt die Seite nicht von selbst neu, solange ein generiertes Passwort darauf
|
||
steht; sie fragt (#013)
|
||
- Eine Anfrage unter `/api/` ohne Anmeldung bekommt `401` statt einer Weiterleitung auf die
|
||
Anmeldeseite — ein `fetch` folgte ihr und hielt die HTML-Antwort für einen Erfolg (#013)
|
||
- Zuweisen lässt sich ein Lauf nur an jemanden, der ihn auch öffnen könnte; die Auswahl zeigt keine
|
||
Bearbeiter fremder Kunden mehr (#013)
|
||
- „Nicht zutreffend“ und „fehlgeschlagen“ lassen sich mit einem Klick zurücknehmen. Vorher sah es
|
||
danach aus, als wäre nichts gewählt, während in der Datenbank weiter der alte Zustand stand (#013)
|
||
- Im QR steht ausschließlich `{APP_URL}/t/{tagCode}` — kein Name, keine Seriennummer, kein
|
||
Besitzer. Ein Aufkleber hängt jahrelang sichtbar am Gerät und wird von jedem Telefon gelesen;
|
||
was darauf steht, ist veröffentlicht (#014)
|
||
- Der QR wird lokal erzeugt, nie über eine externe API: die bekäme mit jedem Aufruf den Bestand an
|
||
Tag-Codes geliefert (#014)
|
||
- Das WebAssembly des QR-Lesers kommt aus dem eigenen Haus statt aus einem CDN — die
|
||
Content-Security-Policy erlaubt nur `connect-src 'self'`, und die Anwendung soll ohne Internet
|
||
laufen (#014)
|
||
- Ein Tag, ein Etikett und eine Geräteseite eines fremden Kunden sind nicht erreichbar; „gibt es
|
||
nicht“ und „darfst du nicht“ sind dieselbe Antwort (#014)
|
||
- In der Druckansicht erscheint vom Mitarbeiter nur Name, UPN und Abteilung — das Lesemodell holt
|
||
gar nichts anderes erst. Ein Ausdruck liegt herum; was darauf steht, ist aus der Hand gegeben
|
||
(#015)
|
||
- Für den Ausdruck entsteht **kein** generiertes Passwort: wo in einem Vorlagentext
|
||
`{{generiertes_passwort}}` steht, erscheint `[Passwort – nicht gespeichert]`. Zwei Ausdrucke
|
||
desselben Laufs sind deshalb Zeichen für Zeichen gleich — der Test prüft genau das (#015)
|
||
- Die Archivsuche setzt jeden Wert als Parameter und maskiert `%`, `_` und `\` für `ILIKE`: die
|
||
Suche nach „50 %“ trifft nicht „5099“ (#015)
|
||
- Das Bind-Passwort einer Verzeichnisquelle wird mit AES-256-GCM verschlüsselt, erreicht keine
|
||
Antwort und kein Log: Fehlermeldungen der LDAP-Bibliothek werden gefiltert, bevor sie gespeichert
|
||
werden, und die Ausnahme trägt keine `cause` — sonst stünde die ganze Kette im Server-Log (#016)
|
||
- Gespeichert werden nur die zugeordneten Attribute: keine Passwörter, keine
|
||
Gruppenmitgliedschaften (#016)
|
||
- Die Hostnamen-Prüfung von TLS lässt sich nicht abschalten; ein Test hält fest, dass weder
|
||
`rejectUnauthorized` noch `checkServerIdentity` gesetzt werden (#016)
|
||
- Das Verzeichnis gibt es nur im Modus Intern — Reiter, Seite und Dienst prüfen das je selbst (#016)
|
||
- Der Abgleich deaktiviert niemanden, wenn sich **kein einziger** gelesener Eintrag zuordnen ließ:
|
||
ein falsch gesetztes Kennungsattribut hätte sonst die gesamte Belegschaft abgeschaltet und dabei
|
||
Erfolg gemeldet (#016)
|
||
- Übersprungene Einträge werden nicht deaktiviert: sie standen im Ergebnis, nur ohne brauchbare
|
||
Kennung — wer sie mit abschaltete, nähme einem anwesenden Menschen den Zugang (#016)
|
||
- Ergebniscodes des Verzeichnisses werden in Sätze übersetzt: falsches Passwort, fehlendes Leserecht
|
||
und ein unbekannter Basis-DN sahen vorher gleich aus (#016)
|