fix: close remaining security gaps, test fixes, frontend integration, event bus
Check Cross-Plugin Imports / check (push) Has been cancelled
Check Cross-Plugin Imports / check (push) Has been cancelled
- RCE: move _check_dangerous_imports() BEFORE exec_module() in plugins.py - verify_ws_origin: reject empty Origin header when CORS configured - Test: ai_app fixture with permission_registry init for ai_assistant - Test: login_client sets CSRF token + Origin as client default headers - Test: SESSION_COOKIE_SECURE=false override + get_settings.cache_clear() - Test: asyncio_default_test_loop_scope=session fixes event loop closed - Test: fix 15 assertions (paths, variables, auth expectations) - Frontend: integrate SavedFilterBar in ContactsList, Mail, Calendar - Frontend: integrate TagSelector in ContactsList, Mail, Calendar - Event Bus: add 4 subscribers in system_notif (conversation/participant/reaction) - Docs: update all analysis reports and FIX-PLAN-V2 to current state
This commit is contained in:
+70
-49
@@ -1,61 +1,82 @@
|
||||
# Test Report — P2-3: Commands und Statusmaschinen Phase 1
|
||||
# Test Report — LeoCRM Fix Branch
|
||||
|
||||
## Task
|
||||
Implement Command Pattern for Contacts domain + State Machine for Contact and Workflow entities.
|
||||
|
||||
## Files Created
|
||||
- `app/commands/__init__.py` — Command package init
|
||||
- `app/commands/base.py` — CommandResult + BaseCommand (template method pattern)
|
||||
- `app/commands/contact_commands.py` — Create/Update/Delete/Merge contact commands
|
||||
- `app/core/state_machine.py` — Generic StateMachine + Contact/Workflow state definitions
|
||||
- `tests/test_commands.py` — Tests for all commands and state machine
|
||||
|
||||
## Files Modified
|
||||
- `app/routes/contacts.py` — Routes now use Commands instead of direct service calls
|
||||
- `app/models/contact.py` — Added `status` field for state machine
|
||||
- `app/schemas/contact.py` — Added `status` field to ContactCreate/ContactUpdate/ContactResponse
|
||||
**Date**: 2026-07-27
|
||||
**Branch**: main (leocrm-fix)
|
||||
|
||||
## Test Results
|
||||
|
||||
### State Machine Tests
|
||||
- ✅ `test_can_transition_allowed` — valid transitions return True
|
||||
- ✅ `test_can_transition_disallowed` — invalid transitions return False
|
||||
- ✅ `test_transition_success` — valid transition returns new state
|
||||
- ✅ `test_transition_invalid_raises` — invalid transition raises StateMachineError
|
||||
- ✅ `test_transition_unknown_state_raises` — unknown state raises StateMachineError
|
||||
- ✅ `test_workflow_state_machine_transitions` — workflow transitions correct
|
||||
- ✅ `test_custom_state_machine` — custom transitions work
|
||||
### Backend: AI Copilot Tests (tests/test_ai_copilot.py)
|
||||
|
||||
### CommandResult Tests
|
||||
- ✅ `test_ok_result` — ok() creates successful result
|
||||
- ✅ `test_ok_with_events` — ok() with events
|
||||
- ✅ `test_fail_result` — fail() creates failed result
|
||||
```
|
||||
76 passed, 2 warnings in 63.31s
|
||||
```
|
||||
|
||||
### CreateContactCommand Tests
|
||||
- ✅ `test_create_contact_admin_success` — admin creates contact, audit + outbox event
|
||||
- ✅ `test_create_contact_viewer_denied` — viewer denied
|
||||
- ✅ `test_create_contact_with_invalid_status` — invalid status rejected
|
||||
**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 ✅
|
||||
|
||||
### UpdateContactCommand Tests
|
||||
- ✅ `test_update_contact_admin_success` — admin updates contact, audit + outbox event
|
||||
- ✅ `test_update_contact_not_found` — not found error
|
||||
- ✅ `test_update_contact_viewer_denied` — viewer denied
|
||||
**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)
|
||||
|
||||
### DeleteContactCommand Tests
|
||||
- ✅ `test_soft_delete_contact_admin_success` — soft delete works, audit created
|
||||
- ✅ `test_hard_delete_contact_admin_success` — hard delete works, event enqueued
|
||||
- ✅ `test_delete_contact_not_found` — not found error
|
||||
- ✅ `test_delete_contact_viewer_denied` — viewer denied
|
||||
### Frontend: TypeScript Type Check
|
||||
|
||||
### MergeContactsCommand Tests
|
||||
- ✅ `test_merge_contacts_admin_success` — merge works, audit + outbox event
|
||||
- ✅ `test_merge_same_contact_fails` — self-merge rejected
|
||||
- ✅ `test_merge_contacts_viewer_denied` — viewer denied
|
||||
- ✅ `test_merge_contact_not_found` — not found error
|
||||
```
|
||||
cd frontend && npx tsc --noEmit
|
||||
# Exit code 0 — no errors
|
||||
```
|
||||
|
||||
## Compilation Check
|
||||
`python -m py_compile` on all new/modified files.
|
||||
### 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
|
||||
Commands execute correctly when called directly with AsyncSession and Redis client.
|
||||
State machine validates transitions and raises on invalid attempts.
|
||||
- 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
|
||||
|
||||
Reference in New Issue
Block a user