fix(PROJ-43): Dry-Run für from_addr/to_addr matcht bare Adressen statt <addr>-Form

dryRunCondition() erwartete faelschlich die Winkelklammer-Form "Name <addr>",
waehrend mail_from/mail_to die Adresse bare speichern - Dry-Run zeigte dadurch
immer 0 Treffer fuer Adress-Regeln, obwohl der Live-Matcher (routeBareAddr)
korrekt matcht. QA-Ergebnisse (Bug-1) in die Feature-Spec uebernommen.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
sysops
2026-07-04 11:57:21 +02:00
co-authored by Claude Sonnet 5
parent 04e5b0f74a
commit 4c92587b60
4 changed files with 129 additions and 4 deletions
@@ -218,7 +218,57 @@ Keine Index-Änderung nötig (reine PostgreSQL-Aggregation).
_To be added by /architecture_
## QA Test Results
_To be added by /qa_
**Getestet:** 2026-07-04 auf Testserver 192.168.1.132 (Binary v0.9.1, deployt 2026-07-03).
Test-Accounts: `qa-superadmin` (superadmin), `qa-da-t1` (domain_admin Tenant 1),
`qa-da-t3` (domain_admin Tenant 3) — dedizierte QA-User, Passwörter für den Test gesetzt
(siehe Testdaten-Hinweis unten). **Gesamtergebnis: BESTANDEN** (alle testbaren AC grün,
1 Minor-Beobachtung).
### Ergebnis je Acceptance Criterion
- [x] **Täglicher Job pro Tag/Quelle** — BESTANDEN. `archivmail reconcile --date 2026-07-03`
läuft, berechnet pro Bucket (`smtp`, `imap:<id>`, `import`) die Tages-Zahl. Ausgabe:
`reconcile: complete days=1 threshold_pct=50 anomalies_total=1`.
- [x] **IMAP Soll/Ist** — BESTANDEN (mit dokumentierter Spec-Abweichung). `expected_count`
ist der SUM(last_uid)-Proxy pro Konto (kein zusätzl. IMAP-Login), z.B. imap:1 exp=2288,
imap:4 exp=116371. `delta` wird negativ ausgewiesen. Verhalten entspricht Implementation
Note "IMAP Soll/Ist (Abweichung von der Spec)".
- [x] **Persistenz `reconciliation_reports`** — BESTANDEN. Tabelle enthält nach Lauf 12 Zeilen
für 2026-07-03 mit allen Spalten (date, tenant_id, source_type, source_id, expected_count,
archived_count, delta). NULL-fähige tenant_id/source_id-Buckets korrekt getrennt.
- [x] **Admin-Dashboard-Kachel** — Frontend-Komponente vorhanden (`ReconciliationCard.tsx`);
API liefert die vom UI erwartete Struktur (siehe API-Tests). UI visuell nicht separat
durchgeklickt, aber Datenkontrakt verifiziert.
- [x] **Abweichung > Schwellenwert → Alert + Audit** — BESTANDEN. Reconcile erkannte Anomalie:
`source=import date=2026-07-03 archived=0 avg_7d=14.1 threshold=50%`. Audit-Log enthält
`event_type=reconciliation_anomaly` (2 Einträge). Schwelle 50% aus Config greift.
- [x] **CSV-Export** — BESTANDEN. `GET /api/admin/reconciliation/export.csv?days=7` liefert
Header `date,tenant_id,source,expected_count,archived_count,delta` + Zeilen. Audit-Eintrag
`event_type=export` erzeugt.
- [x] **0-Mail-Tage explizit als 0** — BESTANDEN. Tage ohne Aktivität stehen als
`archived_count:0` (nicht `missing`), fehlende Cron-Läufe als `"missing":true` (z.B.
2026-07-04 noch nicht gelaufen). Unterscheidung 0 vs. fehlend sauber.
### Sicherheit / Tenant-Isolation
- **Auth-Bypass:** Ohne Cookie liefern `/api/admin/reconciliation` und `/export.csv` beide
`401 {"error":"missing authorization"}`. BESTANDEN.
- **Tenant-Scoping:** domain_admin Tenant 1 sieht nur Tenant-1-Quellen (imap:1, imap:2, import,
smtp — alle tenant_id 1); domain_admin Tenant 3 sieht nur Tenant-3-Quellen (imap:4, imap:5,
import) und KEINE Tenant-1/2-Daten. superadmin sieht alle inkl. tenant_id=null-Buckets.
Cross-Tenant-Leck: keins. BESTANDEN. Kein `{id}`-Pfadparameter → kein IDOR-Vektor.
### Minor-Beobachtung (kein Blocker)
- **Severity: Low.** `days`-Parameter-Clamping asymmetrisch: `days=90` gibt 90 zurück (Max ok),
aber `days=91`/`days=999` fällt still auf Default **7** zurück statt auf das Maximum 90 zu
clampen. Erwartbarer wäre Clamp auf 90. Reine UX-Feinheit, kein Sicherheits-/Datenproblem.
Repro: `GET /api/admin/reconciliation?days=91` → `{"days":7,...}`.
### Testdaten-Hygiene
- Passwörter der 3 dedizierten `qa-*`-Accounts wurden für den Test auf einen bekannten Wert
gesetzt (bcrypt cost 12, direkt in `users.password_hash`). Keine produktiven/echten
Admin-Accounts angefasst. Kein Server auf 131 berührt. Temp-Datei `/tmp/qa.sql` entfernt.
- Der manuelle `reconcile`-Lauf schrieb reguläre Report-/Audit-Zeilen für 2026-07-03 (echte
Produktivdaten des Testservers) — beabsichtigt, keine Testverschmutzung.
## Deployment
_To be added by /deploy_