Files
ServerKit/backend/tests/test_server_workspace_access.py
Juan Denis 166e9acabf Split servers.py into area modules
The 3,000-line file mixed core server routes with Docker, agent
install/update/fleet and remote host operations. Those sections move
verbatim into servers_docker, servers_agents and servers_remote on the
same blueprint; the registered route map (127 rules, methods and
endpoint names) is identical before and after.

The controller-boundary scan only treated files that create a
Blueprint as controllers, so an area module would have escaped it; it
now also counts files that register routes.
2026-10-10 18:49:59 -04:00

78 lines
3.5 KiB
Python

"""A developer outside a server's workspace must not operate it over REST —
the same rule the Socket.IO server rooms and terminal already enforce."""
from unittest.mock import patch
import pytest
from factories import headers_for, make_server, make_user
@pytest.fixture
def setup(app):
from app import db
from app.services.workspace_service import WorkspaceService
admin = make_user(db, 'swa_admin', 'admin')
member = make_user(db, 'swa_member', 'developer')
outsider = make_user(db, 'swa_outsider', 'developer')
ws = WorkspaceService.create_workspace({'name': 'SWA'}, admin.id)
WorkspaceService.add_member(ws.id, member.id)
mine = WorkspaceService.create_workspace({'name': 'SWA-out'}, outsider.id)
server = make_server(db, name='swa-box', workspace_id=ws.id)
return {'server': server.id, 'member': member.id, 'outsider': outsider.id,
'admin': admin.id, 'own_ws': mine.id}
_ROUTES = [
('post', '/api/v1/servers/{sid}/terminal', {}),
('post', '/api/v1/servers/{sid}/regenerate-token', {}),
('put', '/api/v1/servers/{sid}/workspace', {'workspace_id': '{own_ws}'}),
]
@pytest.mark.parametrize('method,url,body', _ROUTES)
def test_outsider_is_refused(client, setup, method, url, body):
from app.models.server import Server
body = {k: setup['own_ws'] if v == '{own_ws}' else v for k, v in body.items()}
before = Server.query.get(setup['server'])
token_hash, ws_id = before.registration_token_hash, before.workspace_id
with patch('app.services.terminal_service.TerminalService.create_session',
return_value={'success': True}) as create:
resp = getattr(client, method)(url.format(sid=setup['server']), json=body,
headers=headers_for(setup['outsider']))
assert resp.status_code == 404
create.assert_not_called()
after = Server.query.get(setup['server'])
assert after.registration_token_hash == token_hash
assert after.workspace_id == ws_id
@pytest.mark.parametrize('who', ['member', 'admin'])
def test_member_and_admin_can_open_terminal(client, setup, who):
with patch('app.services.terminal_service.TerminalService.create_session',
return_value={'success': True, 'session_id': 's1'}) as create:
resp = client.post(f"/api/v1/servers/{setup['server']}/terminal", json={},
headers=headers_for(setup[who]))
assert resp.status_code == 200
create.assert_called_once()
def test_member_can_regenerateheaders_for(client, setup):
resp = client.post(f"/api/v1/servers/{setup['server']}/regenerate-token",
json={}, headers=headers_for(setup['member']))
assert resp.status_code == 200
assert resp.get_json()['registration_token']
def test_default_workspace_servers_stay_shared(client, setup):
"""Servers created without a context land in the Default workspace, which
nobody joins — developers keep operating them."""
from app import db
from app.services.workspace_service import WorkspaceService
server = make_server(db, name='swa-default',
workspace_id=WorkspaceService.ensure_default_workspace().id)
with patch('app.services.terminal_service.TerminalService.create_session',
return_value={'success': True, 'session_id': 's2'}):
resp = client.post(f'/api/v1/servers/{server.id}/terminal', json={},
headers=headers_for(setup['outsider']))
assert resp.status_code == 200