basyx commited on
Commit
75d4046
·
verified ·
1 Parent(s): 0092d74

Test workspace-scoped API key administration

Browse files
tests/test_api_key_workspace_authorization.py ADDED
@@ -0,0 +1,80 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ import asyncio
4
+ from pathlib import Path
5
+
6
+ from fastapi.testclient import TestClient
7
+
8
+ from app.core.config import Settings
9
+ from app.security.models import WorkspaceMembership
10
+ from app.security.schemas import APIKeyCreate
11
+ from main import create_app
12
+
13
+
14
+ def _settings(tmp_path: Path) -> Settings:
15
+ return Settings(
16
+ _env_file=None,
17
+ auth_enabled=True,
18
+ studio_identity_secret="test-only-studio-identity-secret-material",
19
+ database_url=f"sqlite+aiosqlite:///{tmp_path / 'security.db'}",
20
+ social_database_url=f"sqlite+aiosqlite:///{tmp_path / 'social.db'}",
21
+ social_auto_migrate=True,
22
+ social_worker_enabled=False,
23
+ social_oauth_encryption_key="test-only-encryption-material",
24
+ temp_dir=tmp_path / "temp",
25
+ output_dir=tmp_path / "outputs",
26
+ cleanup_interval_seconds=3600,
27
+ whisper_model="tiny",
28
+ max_workers=1,
29
+ )
30
+
31
+
32
+ def test_api_key_admin_routes_are_workspace_scoped_and_role_gated(tmp_path: Path) -> None:
33
+ settings = _settings(tmp_path)
34
+ application = create_app(settings)
35
+ container = application.state.container
36
+ asyncio.run(container.security_database.initialize())
37
+
38
+ owner_record, owner_secret = asyncio.run(
39
+ container.api_keys.create(
40
+ APIKeyCreate(name="Workspace owner", environment="test", role=None, scopes=[]),
41
+ created_by="tests",
42
+ )
43
+ )
44
+ owner_context = asyncio.run(container.api_keys.authenticate(owner_secret))
45
+ same_workspace_record, _ = asyncio.run(
46
+ container.api_keys.create(
47
+ APIKeyCreate(name="Same workspace key", environment="test", role=None, scopes=[]),
48
+ created_by=owner_record.id,
49
+ workspace_id=owner_context.workspace_id,
50
+ user_id=owner_context.user_id,
51
+ )
52
+ )
53
+ other_record, _ = asyncio.run(
54
+ container.api_keys.create(
55
+ APIKeyCreate(name="Other workspace key", environment="test", role=None, scopes=[]),
56
+ created_by="tests",
57
+ )
58
+ )
59
+
60
+ headers = {"Authorization": f"Bearer {owner_secret}"}
61
+ with TestClient(application) as client:
62
+ listed = client.get("/v1/api-keys", headers=headers)
63
+ assert listed.status_code == 200
64
+ assert listed.json()["total"] == 2
65
+ ids = {item["id"] for item in listed.json()["items"]}
66
+ assert ids == {owner_record.id, same_workspace_record.id}
67
+ assert client.get(f"/v1/api-keys/{other_record.id}", headers=headers).status_code == 404
68
+
69
+ async def downgrade_membership() -> None:
70
+ async with container.security_database.session() as session:
71
+ membership = await session.get(WorkspaceMembership, owner_context.membership_id)
72
+ assert membership is not None
73
+ membership.role = "member"
74
+ await session.commit()
75
+
76
+ asyncio.run(downgrade_membership())
77
+ denied = client.get("/v1/api-keys", headers=headers)
78
+ assert denied.status_code == 403
79
+
80
+ asyncio.run(container.security_database.close())