fix: Phase 1 critical+high fixes (17/18 items)

CRITICAL fixes:
- C1: Error swallowing - throw TransportError on network failure in getEmails/searchEmails
- C2: Recurrence expansion ID delimiter changed from ':' to '::occurrence::'
- C3: Cross-account calendar event UID dedup after multi-account aggregation
- C4: Admin session token revocation via JTI blacklist on logout
- C6: FTS5 schema-drop - add warning log for automatic reindex trigger
- C7: Settings lock - gate updateSetting() with isSettingLocked() check
- C8: Offline push pause - add offline event handler that closes push transports

HIGH fixes:
- H1: Push handler - add ContactCard and FileNode branches
- H2: WS fallback - await state snapshot before reconcileAfterWebSocketFallback
- H3: Auth rate limiting - add checkUserAuthRateLimit to session and token routes
- H4: OAuth logs - strip access_token from error log context
- H7: Template XSS - apply DOMPurify to HTML template body on import
- H8: Secure cookie - derive from x-forwarded-proto, not NODE_ENV
- H9: bcrypt fix - remove bcrypt prefixes from isHashed() so scrypt-only
- H13: calendarTasksEnabled - apply admin gate at runtime in calendar page
- H14: Task mutations - add try/catch error handling to update/delete/toggle
- H18: autoSelectReplyIdentity default changed from false to true

Deferred: P1.3 (C5 auth localStorage encryption) - requires custom Zustand persist adapter.
This commit is contained in:
Bernd Rodler
2026-08-07 12:17:41 +02:00
parent 671857722d
commit a622e3755b
21 changed files with 1450 additions and 40 deletions
+102
View File
@@ -0,0 +1,102 @@
# Wave 0 — Execution Graph
**Run:** 2026-08-07-v1.7.8-baseline
**Skill:** VNCmailgraph
**Commit:** d8bebb531f86cab3507aed2113e8d0e6a03c1aa8
---
## DAG Structure
The graph decomposes the audit into **3 waves**:
### Wave 0 (DONE) — Inventory + Dependency Map
- Output: `inventory.md` + this `graph.md`
- Cost: ~minimal (code exploration, no heavy AI)
### Wave 1 — Per-Feature Audits (16 nodes)
Each node audits ONE feature domain against the **6-lens set** (Correctness, Data-Integrity, Cross-Feature Coupling, Security, Performance, Platform-Parity). Nodes are **independent** (can fan out in parallel) — no feature audit reads another feature's output.
### Wave 2 — Substrate Synergetic Failure Hunt (8 nodes)
After Wave 1 completes, these nodes hunt failures that SPAN features through shared substrate: store-coupling, offline/storage, sync+push, platform-parity, auth/session/entitlement, doc cross-check, cross-feature synthesis, completeness critic.
---
## Wave 1 Node Assignments (16 nodes, fully parallelizable)
| ID | Feature | Source Roots | Key Files | Estimated Complexity |
|----|---------|-------------|-----------|---------------------|
| N01 | Mail/Email | `app/(main)/[locale]/page.tsx`, `components/email/`, `stores/email-store.ts` | email-viewer (5102L), email-composer (3432L), email-list, rich-text-editor, JMAP client (7446L) | **VERY HIGH** |
| N02 | Calendar | `app/(main)/[locale]/calendar/`, `components/calendar/`, `stores/calendar-store.ts` | event-modal (1375L), month/week/day views, recurrence-expansion | **HIGH** |
| N03 | Contacts | `app/(main)/[locale]/contacts/`, `components/contacts/`, `stores/contact-store.ts` | contact-list (615L), contact-detail (625L), vCard import/export | **MEDIUM** |
| N04 | Files | `app/(main)/[locale]/files/`, `components/files/`, `stores/file-store.ts` | file-browser (2022L), WebDAV client, dual storage | **MEDIUM** |
| N05 | Tasks | `stores/task-store.ts`, `components/calendar/task-*.tsx` | Small feature (95L store) | **LOW** |
| N06 | Settings | `app/(main)/[locale]/settings/`, `components/settings/`, `stores/settings-store.ts` | 33 settings components, settings-sync | **HIGH** |
| N07 | Filters/Sieve | `components/filters/`, `stores/filter-store.ts`, `lib/sieve/` | filter-rule-modal (534L), parser (866L), generator | **MEDIUM** |
| N08 | Templates | `components/templates/`, `stores/template-store.ts` | Small feature (153L store) | **LOW** |
| N09 | Identity/Aliases | `components/identity/`, `stores/identity-store.ts` | identity-manager-modal (407L) | **LOW** |
| N10 | AI Assistant | `components/ai/`, `lib/ai/`, `app/api/ai/` | local-client (422L), opencode (164L), retrieval/fusion, local-discovery | **MEDIUM** |
| N11 | Admin | `app/(main)/admin/*`, `lib/admin/`, `stores/admin-tab-store.ts` | 18 lib files, 14 pages, config-manager, audit, plugin-registry | **HIGH** |
| N12 | Plugin System | `components/plugins/`, `stores/plugin-store.ts`, `lib/plugin-sandbox/` | 13 sandbox files, host-api (933L), runtime (636L), types (1092L) | **VERY HIGH** |
| N13 | Pro Shell | `app/(main)/[locale]/pro/`, `components/pro/`, `stores/pro-tab-store.ts` | tab-bar, email/compose tab bodies | **LOW** |
| N14 | Search | `components/search/`, `lib/mail-index/`, `stores/email-store.ts` (search state) | FTS5 index (Electron-only), search-chips, advanced-search-panel | **MEDIUM** |
| N15 | Authentication | `lib/auth/`, `lib/oauth/`, `stores/auth-store.ts` | auth-store (2033L), crypto, OIDC, pairing, impersonation | **HIGH** |
| N16 | Setup Wizard | `app/(main)/setup/*`, `lib/setup/` | session, state, token | **LOW** |
---
## Wave 2 Node Assignments (8 nodes, partially parallelizable)
| ID | Substrate Concern | Scope | Depends On |
|----|-------------------|-------|-----------|
| N20 | Store-Coupling & Cycles | Cross-store dependency analysis: auth-store hub, email↔tabs cycle, client-registry anti-cycle | N01N16 |
| N21 | Offline / Storage | `lib/offline-replica/` + `lib/mail-index/` + RxDB evaluation (§D) | N01, N04, N10, N14 |
| N22 | Sync + Push + Background | JMAP push, web push (PWA), Electron notifications, offline queue replay, connectivity | N01, N02, N06 |
| N23 | Platform Parity | Electron vs PWA vs Native gaps: `isElectronShell()` gate spread, local index, offline replica, notifications | N01N16 |
| N24 | Auth / Session / Entitlement | Token lifecycle, multi-account isolation, feature-gate enforcement, sharing/delegation auth | N15, N11 |
| N25 | Doc Cross-Check | FEATURES.md vs actual code vs policy feature gates | N01N16 |
| N26 | Cross-Feature Synthesis | Combines Wave 1 coupling points + Wave 2 substrate findings → cross-feature failures | N01N25 |
| N27 | Completeness Critic | "What feature, modality, or shared path was NOT covered?" + Fresh-context verify of all CRITICAL/HIGH | N01N26 |
---
## Calibration Plan
Before fanning out all 16 Wave 1 nodes, calibrate on **2 representative nodes**:
1. **N05 (Tasks)** — smallest feature (95 lines), low complexity → calibrate per-node cost lower bound
2. **N15 (Authentication)** — high complexity (2033 lines), the central hub importing 7 stores → calibrate per-node cost upper bound
After calibration, price the full Wave 1 fan-out and report against the AI-cost standing rule.
---
## The 6-Lens Set (applied to every Wave 1 node)
1. **Correctness / Functioning** — trace real code paths for core verbs; do they work as written? error/offline handling?
2. **Data-Integrity** — optimistic UI vs persistence; store↔DB consistency; retention/GC; crash-recovery
3. **Cross-Feature Coupling** — enumerate shared store slices + services touched; each is a candidate synergetic-failure surface
4. **Security** — XSS (email-body → DOM → Electron RCE path), entitlement/permission guards, token/credential logging, sharing authorization
5. **Performance** — virtual scrolling, zoneless CD (Next.js/React: missing memo/useCallback on large lists), worker RPC cost
6. **Platform-Parity**`isElectronShell()` branches, Web Push vs Electron Notification, local index availability, offline replica availability
## Finding Template (all nodes)
```
### [CRITICAL|HIGH|MEDIUM|LOW] Short title
- Category: <feature / substrate / type>
- Location: path/file:line
- Evidence: short quoted snippet or precise description
- Impact: concrete failure scenario (inputs → wrong behavior); cross-feature if applicable
- Recommendation: correct approach
- Confidence: measured | reasoned-not-measured
```
## Key Codebase Anchors
- **No secrets in reports** (§B.0.2) — redact all keys, tokens, secrets
- **`rg` landmine** — use `grep -REn` / Read, never `rg` (mangles `electron``n`)
- **Cursor provenance** (`lib/offline-replica/states.ts`) — branded `ChangesState` / `SnapshotState`
- **Deploy policy** — dev first, never prod-direct
- **AI-cost rule** — ≥30% above baseline → report immediately
- **Security anchors** — DOMPurify sanitization, CSP with per-request nonce, SSRF guard, contextIsolation/sandbox for Electron, plugin bundle integrity + signing