Spaces:
Paused
Paused
Download apps/api/tests/integration/test_authorization.py from mohammed978/teteffd: direct link, hf CLI and curl.
- Browser
- Download file 10.5 kB
-
https://huggingface.co/spaces/mohammed978/teteffd/resolve/main/apps/api/tests/integration/test_authorization.py
- Command line
-
hf download hf://spaces/mohammed978/teteffd/apps/api/tests/integration/test_authorization.py
-
curl -L -o test_authorization.py https://huggingface.co/spaces/mohammed978/teteffd/resolve/main/apps/api/tests/integration/test_authorization.py
10.5 kB
| """Integration tests for RBAC, IDOR prevention, and ownership checks. | |
| Requires a running MongoDB instance. | |
| """ | |
| from __future__ import annotations | |
| import os | |
| from datetime import datetime, timezone | |
| import pytest | |
| from bson import ObjectId | |
| from app.db import mongo | |
| pytestmark = [ | |
| pytest.mark.skipif( | |
| os.environ.get("SKIP_MONGO_TESTS", "1") == "1", | |
| reason="MongoDB not available; set SKIP_MONGO_TESTS=0 to run", | |
| ), | |
| ] | |
| class TestAdminRoutes: | |
| """Verify only admin/superadmin can access admin endpoints.""" | |
| async def test_admin_users_requires_admin(self, client, regular_user_token): | |
| headers = {"Authorization": f"Bearer {regular_user_token}"} | |
| r = await client.get("/api/v1/admin/users", headers=headers) | |
| assert r.status_code == 403 | |
| async def test_admin_users_allows_admin(self, client, admin_token): | |
| headers = {"Authorization": f"Bearer {admin_token}"} | |
| r = await client.get("/api/v1/admin/users", headers=headers) | |
| assert r.status_code == 200 | |
| async def test_admin_users_allows_superadmin(self, client, superadmin_token): | |
| headers = {"Authorization": f"Bearer {superadmin_token}"} | |
| r = await client.get("/api/v1/admin/users", headers=headers) | |
| assert r.status_code == 200 | |
| async def test_admin_stats_requires_admin(self, client, regular_user_token): | |
| headers = {"Authorization": f"Bearer {regular_user_token}"} | |
| r = await client.get("/api/v1/admin/stats", headers=headers) | |
| assert r.status_code == 403 | |
| async def test_admin_audit_logs_requires_admin(self, client, regular_user_token): | |
| headers = {"Authorization": f"Bearer {regular_user_token}"} | |
| r = await client.get("/api/v1/admin/audit-logs", headers=headers) | |
| assert r.status_code == 403 | |
| class TestPrivilegeEscalation: | |
| """Verify non-superadmin cannot promote to admin/superadmin.""" | |
| async def test_admin_cannot_promote_to_superadmin(self, client, admin_token, regular_user): | |
| headers = {"Authorization": f"Bearer {admin_token}"} | |
| uid = str(regular_user["_id"]) | |
| r = await client.patch( | |
| f"/api/v1/admin/users/{uid}", | |
| json={"role": "superadmin"}, | |
| headers=headers, | |
| ) | |
| assert r.status_code == 403 | |
| async def test_admin_cannot_promote_to_admin(self, client, admin_token, pending_user): | |
| """Non-superadmin admin cannot grant admin role.""" | |
| headers = {"Authorization": f"Bearer {admin_token}"} | |
| uid = str(pending_user["_id"]) | |
| r = await client.patch( | |
| f"/api/v1/admin/users/{uid}", | |
| json={"role": "admin"}, | |
| headers=headers, | |
| ) | |
| assert r.status_code == 403 | |
| async def test_superadmin_can_promote(self, client, superadmin_token, regular_user): | |
| headers = {"Authorization": f"Bearer {superadmin_token}"} | |
| uid = str(regular_user["_id"]) | |
| r = await client.patch( | |
| f"/api/v1/admin/users/{uid}", | |
| json={"role": "admin"}, | |
| headers=headers, | |
| ) | |
| assert r.status_code == 200 | |
| assert r.json()["role"] == "admin" | |
| class TestIDOR: | |
| """Verify users cannot access other users' data.""" | |
| async def _create_user_conversation(self, token: str, client) -> str: | |
| headers = {"Authorization": f"Bearer {token}"} | |
| r = await client.post( | |
| "/api/v1/chat/conversations", | |
| json={"title": "My Chat"}, | |
| headers=headers, | |
| ) | |
| assert r.status_code == 201 | |
| return r.json()["id"] | |
| async def test_cannot_access_other_conversation(self, client, regular_user_token, admin_token): | |
| uid1 = await self._create_user_conversation(regular_user_token, client) | |
| headers = {"Authorization": f"Bearer {admin_token}"} | |
| r = await client.get(f"/api/v1/chat/conversations/{uid1}", headers=headers) | |
| assert r.status_code == 404 | |
| async def test_cannot_delete_other_conversation(self, client, regular_user_token, admin_token): | |
| cid = await self._create_user_conversation(regular_user_token, client) | |
| headers = {"Authorization": f"Bearer {admin_token}"} | |
| r = await client.delete(f"/api/v1/chat/conversations/{cid}", headers=headers) | |
| assert r.status_code == 404 | |
| async def test_cannot_react_to_other_message(self, client, regular_user_token, admin_token): | |
| # Create conversation as regular user | |
| cid = await self._create_user_conversation(regular_user_token, client) | |
| headers = {"Authorization": f"Bearer {regular_user_token}"} | |
| # Post a message | |
| r = await client.post( | |
| f"/api/v1/chat/conversations/{cid}/messages", | |
| json={"content": "Hello", "role": "user"}, | |
| headers=headers, | |
| ) | |
| mid = r.json()["id"] | |
| # Admin tries to react (should have no ownership of the conversation) | |
| admin_headers = {"Authorization": f"Bearer {admin_token}"} | |
| r = await client.post( | |
| f"/api/v1/chat/conversations/{cid}/messages/{mid}/react", | |
| json={"reaction": "like"}, | |
| headers=admin_headers, | |
| ) | |
| assert r.status_code == 404 # conversation not found for admin | |
| async def test_cannot_access_other_canvas(self, client, regular_user_token, admin_token): | |
| headers = {"Authorization": f"Bearer {regular_user_token}"} | |
| r = await client.post( | |
| "/api/v1/canvas", | |
| json={"title": "My Canvas", "type": "document"}, | |
| headers=headers, | |
| ) | |
| canvas_id = r.json()["id"] | |
| admin_headers = {"Authorization": f"Bearer {admin_token}"} | |
| r = await client.get(f"/api/v1/canvas/{canvas_id}", headers=admin_headers) | |
| assert r.status_code == 404 | |
| async def test_cannot_access_other_memory(self, client, regular_user_token, admin_token): | |
| headers = {"Authorization": f"Bearer {regular_user_token}"} | |
| r = await client.post( | |
| "/api/v1/memory", | |
| json={"kind": "long_term", "content": "My secret"}, | |
| headers=headers, | |
| ) | |
| assert r.status_code == 201 | |
| admin_headers = {"Authorization": f"Bearer {admin_token}"} | |
| r = await client.get("/api/v1/memory", headers=admin_headers) | |
| assert r.status_code == 200 | |
| data = r.json() | |
| # Admin should see their own memories (empty), not the other user's | |
| assert len(data) == 0 | |
| class TestPendingUserAccess: | |
| """Verify pending users are blocked from creating content.""" | |
| async def test_pending_user_cannot_create_conversation(self, client, pending_user_token): | |
| headers = {"Authorization": f"Bearer {pending_user_token}"} | |
| r = await client.post( | |
| "/api/v1/chat/conversations", | |
| json={"title": "Test"}, | |
| headers=headers, | |
| ) | |
| assert r.status_code == 403 | |
| async def test_pending_user_cannot_stream(self, client, pending_user_token): | |
| headers = {"Authorization": f"Bearer {pending_user_token}"} | |
| r = await client.post( | |
| "/api/v1/chat/conversations/000000000000000000000000/stream", | |
| json={"content": "Hello"}, | |
| headers=headers, | |
| ) | |
| assert r.status_code == 403 | |
| async def test_pending_user_cannot_research(self, client, pending_user_token): | |
| headers = {"Authorization": f"Bearer {pending_user_token}"} | |
| r = await client.post( | |
| "/api/v1/research/run", | |
| json={"query": "test", "maxSources": 3}, | |
| headers=headers, | |
| ) | |
| assert r.status_code == 403 | |
| async def test_pending_user_cannot_upload(self, client, pending_user_token): | |
| headers = {"Authorization": f"Bearer {pending_user_token}"} | |
| r = await client.post( | |
| "/api/v1/attachments", | |
| files={"file": ("test.txt", b"hello", "text/plain")}, | |
| headers=headers, | |
| ) | |
| # pending user CAN upload files (no enforce_approval on upload) | |
| # but should they be able to? Let's verify the current behavior | |
| assert r.status_code in (201, 403) | |
| class TestSystemPromptProtection: | |
| """Verify system prompt content is never leaked to non-admin users.""" | |
| async def test_non_admin_cannot_list_prompts(self, client, regular_user_token): | |
| headers = {"Authorization": f"Bearer {regular_user_token}"} | |
| r = await client.get("/api/v1/system-prompts", headers=headers) | |
| assert r.status_code == 403 | |
| async def test_non_admin_cannot_get_prompt(self, client, regular_user_token): | |
| headers = {"Authorization": f"Bearer {regular_user_token}"} | |
| r = await client.get("/api/v1/system-prompts/000000000000000000000000", headers=headers) | |
| assert r.status_code == 403 | |
| async def test_admin_can_list_prompts(self, client, admin_token): | |
| headers = {"Authorization": f"Bearer {admin_token}"} | |
| r = await client.get("/api/v1/system-prompts", headers=headers) | |
| assert r.status_code == 200 | |
| async def test_summary_is_public(self, client, regular_user_token): | |
| headers = {"Authorization": f"Bearer {regular_user_token}"} | |
| r = await client.get("/api/v1/system-prompts/summary", headers=headers) | |
| assert r.status_code == 200 | |
| class TestModelAccess: | |
| """Verify model API keys are never leaked.""" | |
| async def test_model_out_never_has_api_key(self, client, regular_user_token, admin_token): | |
| # Create a model as admin | |
| admin_headers = {"Authorization": f"Bearer {admin_token}"} | |
| r = await client.post( | |
| "/api/v1/models", | |
| json={ | |
| "name": "test-model", | |
| "provider": "groq", | |
| "apiKey": "gsk_test_key_12345", | |
| "enabled": True, | |
| }, | |
| headers=admin_headers, | |
| ) | |
| assert r.status_code == 201 | |
| # Regular user lists models | |
| headers = {"Authorization": f"Bearer {regular_user_token}"} | |
| r = await client.get("/api/v1/models", headers=headers) | |
| data = r.json() | |
| assert len(data) > 0 | |
| model = data[0] | |
| assert "apiKey" not in model | |
| assert model.get("hasApiKey") is True | |
| async def test_developer_reveal_requires_superadmin(self, client, admin_token): | |
| headers = {"Authorization": f"Bearer {admin_token}"} | |
| r = await client.post( | |
| "/api/v1/developer/models/000000000000000000000000/reveal", | |
| headers=headers, | |
| ) | |
| assert r.status_code == 403 | |