docs: capture session knowledge not yet in the repo
Externalises what this session held that the migrated repo did not: - vision/threadnet.md: the three capabilities that justify the forks beyond rebranding (AV scanning into encrypted rooms, call-quality defaults with a client-side-only privacy line, expiring guest access via @concierge). - issue 0043 (M5): case-insensitive uniqueness in the matrix-invitation prompt stage — the open residual of ADR-0011. - issue 0044 (M5): auto-restart consumers on SOPS values-secret change — the footgun behind the on_conflict fix sitting inactive until a manual restart. - issue 0045 (M1): report_event.admin_message_md unset — content reports dead-end with no contact path (verified still open against live config). - sources/protokolle: the raw apo-call diagnosis history, including the four ruled-out hypotheses and the harmful DB write, as the source behind the AAR. STATUS.md regenerated (M5 appears for the first time). validate, gen_status --check, upstream_drift and pruefe_prosa all green in the CI image.
This commit is contained in:
@@ -2,9 +2,9 @@
|
|||||||
|
|
||||||
<!-- Generated by scripts/gen_status.py — do not edit. -->
|
<!-- Generated by scripts/gen_status.py — do not edit. -->
|
||||||
|
|
||||||
## Issues (36 open, 0 closed)
|
## Issues (39 open, 0 closed)
|
||||||
|
|
||||||
Verteilung: M1 9 · M2 25 · M4 2
|
Verteilung: M1 10 · M2 25 · M4 2 · M5 2
|
||||||
|
|
||||||
| Issue | Status | Meilenstein | Priorität | Title |
|
| Issue | Status | Meilenstein | Priorität | Title |
|
||||||
|---|---|---|---|---|
|
|---|---|---|---|---|
|
||||||
@@ -44,6 +44,9 @@ Verteilung: M1 9 · M2 25 · M4 2
|
|||||||
| [0040](docs/issues/0040-neckbeard-rueckmeldungen-einreichen.md) | open | M2 | low | neckbeard-Rückmeldungen aus dem Feldtest einreichen |
|
| [0040](docs/issues/0040-neckbeard-rueckmeldungen-einreichen.md) | open | M2 | low | neckbeard-Rückmeldungen aus dem Feldtest einreichen |
|
||||||
| [0041](docs/issues/0041-wartegrund-der-importierten-waiting-issues.md) | open | M2 | low | wartegrund der 7 importierten waiting-Issues präzisieren |
|
| [0041](docs/issues/0041-wartegrund-der-importierten-waiting-issues.md) | open | M2 | low | wartegrund der 7 importierten waiting-Issues präzisieren |
|
||||||
| [0042](docs/issues/0042-migration-in-betrieb-nehmen-push-spiegel-schedule.md) | open | M2 | high | Migration in Betrieb nehmen: Push, erster Spiegel-Lauf, CI-Schedule |
|
| [0042](docs/issues/0042-migration-in-betrieb-nehmen-push-spiegel-schedule.md) | open | M2 | high | Migration in Betrieb nehmen: Push, erster Spiegel-Lauf, CI-Schedule |
|
||||||
|
| [0043](docs/issues/0043-invitation-flow-eindeutigkeit-case-insensitiv.md) | open | M5 | medium | Invitation-Flow: case-insensitive Eindeutigkeitsprüfung im Prompt-Stage |
|
||||||
|
| [0044](docs/issues/0044-sops-secret-aenderung-startet-dienst-nicht-neu.md) | open | M5 | low | SOPS-Values-Secret-Änderung startet den konsumierenden Dienst nicht neu |
|
||||||
|
| [0045](docs/issues/0045-report-event-kein-kontaktweg-fuer-melder.md) | open | M1 | low | Inhalts-Meldung führt ins Leere: kein Kontaktweg für Melder |
|
||||||
|
|
||||||
## Active design docs (0)
|
## Active design docs (0)
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
---
|
||||||
|
type: issue
|
||||||
|
id: "0043"
|
||||||
|
status: open
|
||||||
|
created: 2026-08-11
|
||||||
|
milestone: M5
|
||||||
|
priority: medium
|
||||||
|
area: security
|
||||||
|
related: [docs/adr/0011-enrollment-localpart-kollision-verweigern.md]
|
||||||
|
---
|
||||||
|
# Invitation-Flow: case-insensitive Eindeutigkeitsprüfung im Prompt-Stage
|
||||||
|
|
||||||
|
> Offener Rest aus [ADR-0011](../adr/0011-enrollment-localpart-kollision-verweigern.md); GitLab-seitig als [gitops#61](https://git.lab/axion1337.chat/axion1337.chat-gitops/-/issues/61) verfolgt.
|
||||||
|
|
||||||
|
## Problem / Motivation
|
||||||
|
|
||||||
|
Die Kontoübernahme über kollidierende Localparts ist geschlossen — MAS steht auf
|
||||||
|
`on_conflict: fail` (ADR-0011, live nach MAS-Neustart). Das ist die harte
|
||||||
|
Sicherheitsgrenze, aber sie greift erst **beim Login**: Ein Nutzer, der bei der
|
||||||
|
Registrierung einen bereits vergebenen Namen (oder eine Schreibweise-Variante wie
|
||||||
|
`boje` neben `Boje`) wählt, bekommt kein Feedback im Flow, sondern läuft später in
|
||||||
|
einen fehlgeschlagenen Login. Authentiks eigene Eindeutigkeit ist case-sensitive
|
||||||
|
und deckt Kollisionen mit bestehenden Matrix-Konten nicht ab.
|
||||||
|
|
||||||
|
## Acceptance
|
||||||
|
|
||||||
|
- Der `matrix-invitation`-Flow prüft im Prompt-Stage den gewünschten
|
||||||
|
Benutzernamen **case-insensitive** gegen bestehende Konten und weist eine
|
||||||
|
Kollision schon bei der Registrierung sichtbar ab.
|
||||||
|
- Als Blueprint reproduzierbar (`apps/authentik/authentik-blueprints.yaml`), nicht
|
||||||
|
nur als Klick im Admin-UI.
|
||||||
|
- Gegenprobe: Registrierung mit einem existierenden Namen in abweichender
|
||||||
|
Schreibweise scheitert im Flow, nicht erst beim Login.
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
Rein defensive Ergänzung / UX — der Übernahme-Vektor selbst ist bereits zu.
|
||||||
|
Deshalb M5 (Härtung, nicht Reparatur) und `priority: medium`.
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
---
|
||||||
|
type: issue
|
||||||
|
id: "0044"
|
||||||
|
status: open
|
||||||
|
created: 2026-08-11
|
||||||
|
milestone: M5
|
||||||
|
priority: low
|
||||||
|
area: infrastructure
|
||||||
|
related: [docs/adr/0011-enrollment-localpart-kollision-verweigern.md]
|
||||||
|
---
|
||||||
|
# SOPS-Values-Secret-Änderung startet den konsumierenden Dienst nicht neu
|
||||||
|
|
||||||
|
## Problem / Motivation
|
||||||
|
|
||||||
|
Beim Ausrollen des `on_conflict: fail`-Fixes (ADR-0011) trat ein Footgun zutage:
|
||||||
|
Flux aktualisierte das SOPS-verwaltete Secret `ess-mas-values-secret`, aber der
|
||||||
|
laufende MAS-Pod war älter als die Änderung und behielt die alte Config im
|
||||||
|
Speicher — MAS liest seine Config nur beim Start. Der Sicherheits-Fix stand auf
|
||||||
|
der Platte, war im Prozess aber **nicht aktiv**, bis ein manueller
|
||||||
|
`kubectl rollout restart` folgte. „committet ≠ deployed ≠ aktiv."
|
||||||
|
|
||||||
|
Das betrifft nicht nur MAS: jeder Dienst, der ein von Flux/SOPS gepflegtes
|
||||||
|
Values-Secret nur beim Start liest, hat dieselbe stille Lücke. Aktuell ist die
|
||||||
|
einzige Absicherung die in ADR-0011 festgeschriebene **manuelle** Restart-und-
|
||||||
|
Verifikations-Regel — leicht zu vergessen.
|
||||||
|
|
||||||
|
## Acceptance
|
||||||
|
|
||||||
|
- Änderungen an einem konsumierten Values-Secret lösen automatisch einen Rollout
|
||||||
|
des abhängigen Deployments aus (z. B. Checksum-/Hash-Annotation auf dem
|
||||||
|
Pod-Template, ein Reloader wie stakater/Reloader, oder ein
|
||||||
|
`configMapGenerator`/`secretGenerator`-Namenshash in kustomize).
|
||||||
|
- Verifiziert an MAS: Änderung am Secret → neuer Pod ohne Handeingriff, jünger als
|
||||||
|
die Änderung.
|
||||||
|
- Mindestens MAS abgedeckt; idealerweise als wiederverwendbares Muster für weitere
|
||||||
|
von SOPS-Secrets gespeiste Dienste.
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
Automatisiert nur den bereits in ADR-0011 vorgeschriebenen manuellen Schritt —
|
||||||
|
daher `priority: low`. M5, weil die Fähigkeit (Auto-Reload) neu ist, nicht kaputt.
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
---
|
||||||
|
type: issue
|
||||||
|
id: "0045"
|
||||||
|
status: open
|
||||||
|
created: 2026-08-11
|
||||||
|
milestone: M1
|
||||||
|
priority: low
|
||||||
|
area: element
|
||||||
|
related: []
|
||||||
|
---
|
||||||
|
# Inhalts-Meldung führt ins Leere: kein Kontaktweg für Melder
|
||||||
|
|
||||||
|
## Problem / Motivation
|
||||||
|
|
||||||
|
Der Web-Client kann Inhalte melden (`report_event`), aber
|
||||||
|
`report_event.admin_message_md` ist in `element-values.yaml` **nicht gesetzt**
|
||||||
|
(Stand 2026-08-11 gegen die Live-Config geprüft). Wer etwas meldet, sieht danach
|
||||||
|
keinen Kontaktweg — keine Angabe, an wen die Meldung geht oder wo man nachfassen
|
||||||
|
kann. Für einen Community-Betrieb mit Moderation (Draupnir) ist das eine offene
|
||||||
|
Kante: Melden funktioniert technisch, führt für den Nutzer aber ins Leere.
|
||||||
|
|
||||||
|
## Acceptance
|
||||||
|
|
||||||
|
- `report_event.admin_message_md` in
|
||||||
|
`apps/production/custom-configs/element-values.yaml` gesetzt, mit einem echten
|
||||||
|
Kontakt-/Meldeweg (Moderationsraum oder Kontaktadresse).
|
||||||
|
- Live sichtbar: nach einer Meldung erscheint der hinterlegte Hinweis.
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
Braucht **eine Angabe von sorb**: welcher Raum bzw. Kontakt der Meldeweg sein
|
||||||
|
soll. Danach ist es eine Zeile Config. Bewusst nicht auf `waiting` gesetzt, weil
|
||||||
|
noch nicht begonnen — der fehlende Input ist im Text benannt.
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
# Protokoll — Diagnose „@apo kann nicht telefonieren" (2026-08-11)
|
||||||
|
|
||||||
|
Rohes Verlaufsprotokoll der Fehlersuche, als Quelle zum AAR
|
||||||
|
[docs/aar/2026-08-11-apo-calls-profile-zeile.md](../../aar/2026-08-11-apo-calls-profile-zeile.md).
|
||||||
|
Der AAR verdichtet zu Befund und Lehre; dieses Protokoll hält die tatsächliche
|
||||||
|
Reihenfolge fest — **inklusive der Irrwege**, weil die Frage „wie konnte sich die
|
||||||
|
Diagnose so lange verlaufen?" nur am ungekürzten Weg zu beantworten ist.
|
||||||
|
|
||||||
|
## Ausgangslage
|
||||||
|
|
||||||
|
`@apo` konnte sich anmelden und schreiben, aber kein Call kam zustande. Dem
|
||||||
|
vorausgegangen war ein längerer Vorgang mit mehreren manuellen Eingriffen an
|
||||||
|
`@apo`s Konto, die das Problem nicht gelöst hatten — darunter ein selbst
|
||||||
|
ausgedachter, in die MAS-Produktions-DB geschriebener `sub`-Wert und das Beenden
|
||||||
|
aller Sitzungen. Diese Eingriffe waren real schädlich und haben Vertrauen und Zeit
|
||||||
|
gekostet; sie sind der Grund, warum der Nutzer auf strukturiertem Vorgehen bestand.
|
||||||
|
|
||||||
|
## Die vier Irrwege (jeder an einer Messung gescheitert)
|
||||||
|
|
||||||
|
1. **Fehlende Cross-Signing-Verifikation.** Entkräftet: `sorb`/`clark` haben
|
||||||
|
ebenfalls keine und telefonieren.
|
||||||
|
2. **Kaputter Browser-/Client-Zustand.** Entkräftet: ein frischer Client zeigte
|
||||||
|
dasselbe Verhalten → an das Konto gebunden, nicht an den lokalen Zustand.
|
||||||
|
3. **Safari-Spezifik.** Zurückgezogen.
|
||||||
|
4. **MAS↔Synapse-Geräte-Desync.** Entkräftet: beide Seiten kannten dieselben drei
|
||||||
|
Geräte.
|
||||||
|
|
||||||
|
Das Muster war der eigentliche Fehler: aus dem, was serverseitig sichtbar war,
|
||||||
|
wurde wiederholt auf eine Ursache geschlossen, ohne sie an einem funktionierenden
|
||||||
|
Konto gegenzuprüfen. Der teuerste Einzelfall war der erfundene `sub`-Wert —
|
||||||
|
`clark` hätte die Formel sofort widerlegt, wäre sie vor dem Schreiben geprüft
|
||||||
|
worden.
|
||||||
|
|
||||||
|
## Die Kette, die zum Fund führte
|
||||||
|
|
||||||
|
1. **Vergleich statt Einzelbetrachtung.** `open_id_tokens` über *alle* aktiven
|
||||||
|
Nutzer abgefragt: `@apo` = 0, alle anderen zweistellig+. Damit war klar: der
|
||||||
|
Call-Pfad scheitert für `@apo` am allerersten Schritt (kein OpenID-Token).
|
||||||
|
2. **Confounder entfernt.** Der Testraum war **unverschlüsselt** — Krypto/
|
||||||
|
Cross-Signing damit in einem Schritt raus (der ganze Block „18 Pseudo-Geräte
|
||||||
|
aus 6 Resets" war eine Sackgasse).
|
||||||
|
3. **Live-Mitschnitt beim echten Call-Klick.** Ergebnis: *nichts* — kein
|
||||||
|
`openid/request_token`, kein `call.member`-Event. Beides erzeugt das
|
||||||
|
Element-Call-Widget-iframe; beide fehlten → das iframe wird nie aktiv.
|
||||||
|
4. **Der Nutzer-Hinweis „Anzeigename konnte nicht gesetzt werden"** lieferte den
|
||||||
|
500er mit vollständigem Stacktrace: `TypeError: 'NoneType' object is not
|
||||||
|
subscriptable` in `_check_profile_size`.
|
||||||
|
5. **Der Kontext-Hinweis des Nutzers** — „`apo` ist ein Konto von vor der
|
||||||
|
Authentik-Integration" — drehte die Suche von „angesammelter Müll" auf
|
||||||
|
„Provisionierungs-Lücke".
|
||||||
|
|
||||||
|
## Grundursache und Fix
|
||||||
|
|
||||||
|
`@apo` fehlte die Zeile in Synapses `profiles`-Tabelle (Deaktivieren löscht das
|
||||||
|
Profil, Reaktivieren legt es nicht neu an; `@apo` ging durch sechs Resets).
|
||||||
|
Fehlende Zeile → jeder Displayname-Schreibvorgang crasht → kein Displayname →
|
||||||
|
Element-Call-Widget initialisiert nie → kein OpenID-Token, kein Call. Fix: die
|
||||||
|
fehlende Registrierungs-Default-Zeile per `INSERT` nachgetragen, an `clark`/
|
||||||
|
`calltest01` gegengeprüft. Danach: Displayname setzbar, `open_id_tokens` 0→6, Call
|
||||||
|
verifiziert. `@apo` war der einzige betroffene lebende Nutzer.
|
||||||
|
|
||||||
|
## Nebenstrang: die Sicherheitslücke
|
||||||
|
|
||||||
|
Beim Anlegen des Testkontos entstand die case-sensitive Dublette `boje`/`Boje`.
|
||||||
|
Der Faden führte zu einem Kontoübernahme-Vektor: MAS stand auf
|
||||||
|
`on_conflict: add` und hätte kollidierende Localparts an bestehende Konten
|
||||||
|
verknüpft. Fix `on_conflict: fail` (ADR-0011), erst nach MAS-Neustart aktiv —
|
||||||
|
was die zweite Lehre lieferte: eine SOPS-Secret-Änderung startet den Dienst nicht
|
||||||
|
neu.
|
||||||
|
|
||||||
|
## Was das Protokoll dem AAR voraushat
|
||||||
|
|
||||||
|
Der AAR nennt die Lehren; dieses Protokoll zeigt, dass sie **teuer erkauft** waren:
|
||||||
|
vier eingesammelte Hypothesen und ein schädlicher DB-Schreib gingen dem einen
|
||||||
|
`open_id_tokens`-Vergleich voraus, der die Sache in Minuten entschied. Die Lehre
|
||||||
|
„erst vergleichen, dann schreiben" steht im AAR als Satz — hier steht, warum sie
|
||||||
|
einen Satz wert ist.
|
||||||
@@ -25,6 +25,28 @@ threadnet-operating.
|
|||||||
chirurgische Patches statt Umbauten.
|
chirurgische Patches statt Umbauten.
|
||||||
- CI beweist Releases: Tag → Pipeline → Artefakt, keine Handbuilds.
|
- CI beweist Releases: Tag → Pipeline → Artefakt, keine Handbuilds.
|
||||||
|
|
||||||
|
## Was die Forks über das Rebranding hinaus leisten
|
||||||
|
|
||||||
|
Das Rebranding ist die sichtbarste, aber nicht die eigentliche Rechtfertigung der
|
||||||
|
Forks. Drei Fähigkeiten gehen bewusst über Upstream hinaus und sind der Grund,
|
||||||
|
dass ThreadNet eine eigene Produkt-Linie ist und kein umgefärbtes Element:
|
||||||
|
|
||||||
|
- **Virenprüfung bis in verschlüsselte Räume.** Upstream Element scannt Uploads
|
||||||
|
nur serverseitig und nur in unverschlüsselten Räumen. ThreadNet-Web ruft den
|
||||||
|
Scan client-seitig **beim Senden und beim Empfangen** auf — damit greift die
|
||||||
|
Prüfung auch in verschlüsselten Räumen und DMs, wo der Server den Inhalt nie
|
||||||
|
sieht. Das ist die inhaltliche Begründung des Web-Forks, nicht die Optik.
|
||||||
|
- **Call-Qualität als Voreinstellung, Privatsphäre als Grenze.** threadnet-call
|
||||||
|
hebt die Medien-Defaults an (bis 1440p/60fps, H.264 für Hardware-Beschleunigung
|
||||||
|
v.a. auf iOS/Safari) und lässt die Rauschunterdrückung **bewusst
|
||||||
|
client-seitig** — kein server-seitiges ML, das bereinigtes Audio anderer
|
||||||
|
Teilnehmer verarbeiten würde. Startwerte, keine harten Grenzen; die
|
||||||
|
Privatsphäre-Linie ist die harte.
|
||||||
|
- **Gäste mit Ablaufdatum.** Registrierung läuft ausschließlich über Authentik;
|
||||||
|
der @concierge-Bot macht daraus einen nachvollziehbaren Vorgang mit eingebautem
|
||||||
|
Ablauf und zweiteiliger Berechtigung — die Gruppe entscheidet, der Raum macht
|
||||||
|
sichtbar, wer wen eingeladen hat.
|
||||||
|
|
||||||
## Veröffentlichungsgrad
|
## Veröffentlichungsgrad
|
||||||
|
|
||||||
**Die Forks werden öffentlich** (entschieden 2026-08-06) — aber erst nach einem
|
**Die Forks werden öffentlich** (entschieden 2026-08-06) — aber erst nach einem
|
||||||
|
|||||||
Reference in New Issue
Block a user