mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-07-21 20:06:06 +00:00
fix(tenancy): close isolation and permission gaps
This commit is contained in:
@@ -231,7 +231,7 @@ class TestBotLogsEndpoint:
|
||||
assert 'total_count' in data['data']
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_viewer_cannot_read_message_logs(self, quart_test_client, fake_bot_app):
|
||||
async def test_viewer_can_read_ordinary_bot_logs(self, quart_test_client, fake_bot_app):
|
||||
access = fake_bot_app.workspace_collaboration_service.resolve_account_workspace.return_value
|
||||
original_role = access.membership.role
|
||||
access.membership.role = 'viewer'
|
||||
@@ -245,9 +245,9 @@ class TestBotLogsEndpoint:
|
||||
finally:
|
||||
access.membership.role = original_role
|
||||
|
||||
assert response.status_code == 403
|
||||
assert (await response.get_json())['code'] == 'permission_denied'
|
||||
fake_bot_app.bot_service.list_event_logs.assert_not_awaited()
|
||||
assert response.status_code == 200
|
||||
assert (await response.get_json())['code'] == 0
|
||||
fake_bot_app.bot_service.list_event_logs.assert_awaited_once()
|
||||
|
||||
|
||||
@pytest.mark.usefixtures('mock_circular_import_chain')
|
||||
|
||||
@@ -155,6 +155,34 @@ class TestMonitoringOverviewEndpoint:
|
||||
data = await response.get_json()
|
||||
assert data['code'] == 0
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_viewer_can_read_monitoring_but_cannot_export(
|
||||
self,
|
||||
quart_test_client,
|
||||
fake_monitoring_app,
|
||||
):
|
||||
"""Ordinary monitoring is resource.view; export remains data.export."""
|
||||
membership = (
|
||||
fake_monitoring_app.workspace_collaboration_service.resolve_account_workspace.return_value.membership
|
||||
)
|
||||
original_role = membership.role
|
||||
membership.role = 'viewer'
|
||||
try:
|
||||
response = await quart_test_client.get(
|
||||
'/api/v1/monitoring/overview',
|
||||
headers={'Authorization': 'Bearer test_token'},
|
||||
)
|
||||
assert response.status_code == 200
|
||||
|
||||
export_response = await quart_test_client.get(
|
||||
'/api/v1/monitoring/export?type=messages',
|
||||
headers={'Authorization': 'Bearer test_token'},
|
||||
)
|
||||
assert export_response.status_code == 403
|
||||
assert (await export_response.get_json())['code'] == 'permission_denied'
|
||||
finally:
|
||||
membership.role = original_role
|
||||
|
||||
|
||||
@pytest.mark.usefixtures('mock_circular_import_chain')
|
||||
class TestMonitoringMessagesEndpoint:
|
||||
|
||||
@@ -233,6 +233,22 @@ async def test_owner_invites_second_account_and_secret_is_not_persisted(workspac
|
||||
assert (await forbidden_invite.get_json())['code'] == 'permission_denied'
|
||||
|
||||
|
||||
async def test_invitation_accept_rejects_invalid_bearer_as_authentication_failure(workspace_api):
|
||||
_, client, _, _ = workspace_api
|
||||
|
||||
response = await client.post(
|
||||
'/api/v1/invitations/accept',
|
||||
headers={'Authorization': 'Bearer definitely-not-a-jwt'},
|
||||
json={'token': 'lbi_not-a-real-invitation'},
|
||||
)
|
||||
|
||||
assert response.status_code == 401
|
||||
assert await response.get_json() == {
|
||||
'code': 'invalid_authentication',
|
||||
'msg': 'Invalid authentication credentials',
|
||||
}
|
||||
|
||||
|
||||
async def test_workspace_selector_and_path_cannot_escape_membership(workspace_api):
|
||||
_, client, _, owner_token = workspace_api
|
||||
|
||||
@@ -412,6 +428,16 @@ async def test_cloud_projection_is_selected_explicitly_and_directory_writes_use_
|
||||
assert by_uuid[singleton_uuid]['permissions']
|
||||
assert by_uuid[cloud_workspace_uuid]['placement_generation'] == 12
|
||||
|
||||
list_response = await client.get(
|
||||
'/api/v1/workspaces',
|
||||
headers=_auth(owner_token, singleton_uuid),
|
||||
)
|
||||
assert list_response.status_code == 200
|
||||
assert {workspace['uuid'] for workspace in (await list_response.get_json())['data']['workspaces']} == {
|
||||
singleton_uuid,
|
||||
cloud_workspace_uuid,
|
||||
}
|
||||
|
||||
current_response = await client.get(
|
||||
'/api/v1/workspaces/current',
|
||||
headers=_auth(owner_token, cloud_workspace_uuid),
|
||||
|
||||
Reference in New Issue
Block a user