feat(phase-4): Task 2 — SEC-08 CloudConnectionOut, SEC-09 delete-user cleanup, admin audit writes
- Add CloudConnectionOut Pydantic model (SEC-08): credentials_enc deliberately excluded
- Implement DELETE /api/admin/users/{id} (SEC-09): collects user docs, deletes MinIO
objects best-effort before DB delete; audit log written within same transaction
- Add write_audit_log calls to: create_user (admin.user_created), update_user_status
(admin.user_deactivated/admin.user_activated), update_user_quota (admin.quota_changed),
update_ai_config (admin.ai_provider_assigned), delete_user (admin.user_deleted)
- Add Request param to all admin state-changing handlers for IP extraction
- Fix test_admin_impersonation_not_found: accept 405 in addition to 404/422
(expected: DELETE /users/{id} exists now, so GET returns 405 — no impersonation
route still satisfied, just a different HTTP status for non-existent method)
This commit is contained in:
@@ -320,13 +320,19 @@ async def test_update_ai_config(admin_client):
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_admin_impersonation_not_found(async_client: AsyncClient):
|
||||
"""GET /api/admin/users/impersonate → 404 or 422 (route does not exist)."""
|
||||
"""GET /api/admin/users/impersonate → 404, 422, or 405 (no GET impersonation route).
|
||||
|
||||
Note: 405 is acceptable when DELETE /api/admin/users/{id} exists (Plan 04-07, SEC-09)
|
||||
— the DELETE route is the user-delete endpoint, NOT impersonation. A 405 means
|
||||
GET is not allowed, which satisfies the invariant that no impersonation GET endpoint
|
||||
exists (ADMIN-07).
|
||||
"""
|
||||
# No admin override — just verifying the route doesn't exist at all.
|
||||
resp = await async_client.get("/api/admin/users/impersonate")
|
||||
# 404 = no route; 422 = id parse failed (impersonate is not a UUID) → acceptable
|
||||
# 405 = Method Not Allowed (DELETE /users/{id} exists but no GET handler) → also acceptable
|
||||
# 401/403 = route exists but blocked by auth → NOT acceptable (route should not exist)
|
||||
# We accept 404 or 422 only.
|
||||
assert resp.status_code in {404, 422}
|
||||
assert resp.status_code in {404, 405, 422}
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
||||
Reference in New Issue
Block a user