Phase 5: Outbox DLQ, Monitoring, Consumer-Registry

- Migration 0092: DLQ columns (error_message, failed_at) + consumer_inbox RLS fix
- outbox.py: DLQ logic, replay functions, stats, consumer registry
- app/routes/outbox.py: 5 API endpoints (stats, failed, replay, replay-all, consumer-registry)
- outbox_deliveries tracking per consumer handler
- 18/18 tests passing
This commit is contained in:
Agent Zero
2026-08-02 23:25:54 +02:00
parent 24cb10a7a2
commit 07a99975ec
12 changed files with 1017 additions and 79 deletions
+34 -69
View File
@@ -1,82 +1,47 @@
# Test Report — LeoCRM Fix Branch
# Test Report — Phase 5: Outbox DLQ, Monitoring, Consumer-Registry
**Date**: 2026-07-27
**Branch**: main (leocrm-fix)
## Date: 2026-08-02
## Test Results
### Backend: AI Copilot Tests (tests/test_ai_copilot.py)
## Test Execution
```
76 passed, 2 warnings in 63.31s
cd /a0/usr/workdir/leocrm-fix && python -m pytest tests/test_outbox.py tests/test_outbox_phase5.py -v
```
**AC Tests (all pass):**
- AC1: test_ac1_copilot_query_returns_proposed_actions ✅
- AC2: test_ac2_copilot_execute_action_success ✅
- AC3: test_ac3_copilot_execute_blocked_by_rbac ✅
- AC4: test_ac4_copilot_history_paginated ✅
- AC5: test_ac5_copilot_action_logged_in_audit ✅
- AC6: test_ac6_copilot_tenant_isolation ✅
- AC7: test_ac7_copilot_field_level_permissions ✅
## Results: 18 passed, 0 failed
**Other tests fixed:**
- test_copilot_unauthenticated: Fixed 401→403 for POST (CSRF middleware returns 403)
- test_route_copilot_history_unauthenticated: GET returns 401 (no CSRF needed)
- test_route_copilot_execute_unauthenticated: Fixed 401→403 for POST
- action_mapper tests: Updated /api/v1/companies → /api/v1/contacts (unified contact model)
- llm_client tests: Fixed ai_client → client variable, api_base default ''
- service tests: Updated /api/v1/companies → /api/v1/contacts, PATCH/DELETE return 400 (unsupported)
### Existing Tests (test_outbox.py) — 6/6 passed
- test_enqueue_outbox_event_inserts_pending_row ✅
- test_process_outbox_batch_publishes_events ✅
- test_process_outbox_batch_empty_returns_zero ✅
- test_process_outbox_batch_retry_on_failure ✅
- test_process_outbox_batch_max_attempts_marks_failed ✅
- test_enqueue_multiple_events_and_batch_size ✅
### Frontend: TypeScript Type Check
### Phase 5 Tests (test_outbox_phase5.py) — 12/12 passed
- test_failed_event_has_error_message ✅ (DLQ: error_message + failed_at set)
- test_replay_failed_event ✅ (single replay: failed→pending)
- test_replay_failed_event_not_found ✅ (404 case)
- test_replay_all_failed_events ✅ (bulk replay: 3 events reset)
- test_get_outbox_stats ✅ (counts per status, total, oldest pending age)
- test_get_outbox_stats_empty ✅ (empty tenant returns zeros)
- test_get_failed_events ✅ (failed events with error details)
- test_get_failed_events_pagination ✅ (limit/offset pagination)
- test_get_consumer_registry ✅ (event_name→handler_names mapping)
- test_outbox_deliveries_written_on_success ✅ (status='delivered')
- test_outbox_deliveries_written_on_failure ✅ (status='failed', last_error set)
- test_route_import ✅ (all 5 endpoints registered)
## Syntax Check
```
cd frontend && npx tsc --noEmit
# Exit code 0 — no errors
python -c 'import app.core.outbox; import app.routes.outbox; import app.models.outbox; import app.models.consumer_inbox; import app.models.outbox_delivery'
→ All imports OK
```
### Event Loop Fix
Added `asyncio_default_fixture_loop_scope = "session"` and `asyncio_default_test_loop_scope = "session"` to pyproject.toml to fix 'Event loop is closed' error when running multiple AI copilot tests in sequence.
## Changes Summary
### 1. Backend Security Fixes
- **RCE Dead Code repariert** (`app/routes/plugins.py`): Security-Check (`_check_dangerous_imports`) wurde VOR `exec_module()` verschoben. Zuvor war exec_module vor dem Security-Check, was eine RCE-Lücke war (auch wenn alle Upload-Endpoints deaktiviert waren).
- **verify_ws_origin verschärft** (`app/core/auth.py`): Leerer Origin-Header wird jetzt abgelehnt (return False) wenn CORS konfiguriert ist, statt automatisch akzeptiert zu werden.
### 2. Test Infrastructure Fixes (conftest.py)
- Neuer `ai_app` und `ai_client` Fixture mit `init_permission_registry(active_plugin_names={'ai_assistant'})`
- `login_client` setzt jetzt CSRF-Token und Origin als Client-Default-Header
- `SESSION_COOKIE_SECURE=false` und `SESSION_COOKIE_SAMESITE=lax` werden vor allen Imports gesetzt
- `get_settings.cache_clear()` nach env-Override
- `pyproject.toml`: `asyncio_default_fixture_loop_scope = "session"` und `asyncio_default_test_loop_scope = "session"` hinzugefügt
- `tests/test_ai_copilot.py`: `/api/v1/companies``/api/v1/contacts` (Companies sind Contacts mit type='company'). 15 weitere Test-Fixes (action_mapper paths, llm_client variables, service test paths, unauthenticated test assertions).
### 3. Event Bus Lücken geschlossen
- system_notif/plugin.py: Added conversation.created, participant.joined, participant.left, reaction.added to manifest events list
- Added handler methods: on_conversation_created, on_participant_joined, on_participant_left, on_reaction_added
- Added event titles for new events in _create_system_notification
### 4. Frontend Integration: SavedFilterBar
- ContactsList.tsx: Added SavedFilterBar with entityType="contacts" in middle pane
- Mail.tsx: Added SavedFilterBar with entityType="mail" in mail list pane
- Calendar.tsx: Added SavedFilterBar with entityType="calendar" in calendar view pane
### 5. Frontend Integration: TagSelector
- ContactsList.tsx: Added TagSelector with entityType="contact" in middle pane
- Mail.tsx: Added TagSelector with entityType="file" in mail list pane
- Calendar.tsx: Added TagSelector with entityType="calendar_entry" in calendar view pane
### 6. Event Loop Fix
- pyproject.toml: Added asyncio_default_fixture_loop_scope and asyncio_default_test_loop_scope = "session"
- Fixed 15 pre-existing test failures (action_mapper, llm_client, service tests) caused by unified contact model migration
## Smoke Test
- Backend: All 76 AI copilot tests pass including AC1-AC7
- Frontend: TypeScript compilation passes with 0 errors
- Event bus: system_notif plugin now subscribes to conversation.created, participant.joined/left, reaction.added
- RCE Dead Code: Security-Check (_check_dangerous_imports) wird VOR exec_module() ausgeführt
- verify_ws_origin: Leerer Origin-Header wird abgelehnt bei konfiguriertem CORS
- conftest.py: ai_app/ai_client Fixtures mit ai_assistant Plugin-Aktivierung, CSRF-Token, Origin-Header
- Frontend-Integration: SavedFilterBar und TagSelector in ContactsList, Mail, Calendar integriert
- All 5 API endpoints registered under `/api/v1/outbox/`
- DLQ columns (error_message, failed_at) functional in event_outbox
- Replay functions reset failed events to pending correctly
- outbox_deliveries entries written per-consumer during processing
- Consumer registry reads from event_bus._handlers at runtime
- RLS: tenant context required for all monitoring queries