Add owner-only update controls, a read-only SSH checker and independent systemd deployment services. Build before maintenance; back up code and database; restore on failed deployment. Preserve runtime configuration and gate business writes during the switch.
53 lines
2.3 KiB
Python
53 lines
2.3 KiB
Python
import json
|
|
from types import SimpleNamespace
|
|
from unittest.mock import AsyncMock
|
|
from uuid import uuid4
|
|
|
|
import pytest
|
|
from fastapi import FastAPI
|
|
from fastapi.testclient import TestClient
|
|
|
|
from app.api import system_updates as updates
|
|
from app.core.auth import get_current_user
|
|
|
|
|
|
@pytest.fixture
|
|
def setup(tmp_path, monkeypatch):
|
|
owner = str(uuid4())
|
|
cfg = tmp_path / 'config.json'
|
|
cfg.write_text(json.dumps({'owner_ids': [owner], 'state_dir': str(tmp_path), 'web_url': 'https://gitea.example/repo', 'branch': 'main'}))
|
|
(tmp_path / 'status.json').write_text(json.dumps({'current': {'revision': 'a' * 40}, 'latest': {'revision': 'b' * 40}, 'update': {'status': 'idle'}}))
|
|
monkeypatch.setattr(updates, 'CONFIG_FILE', cfg)
|
|
command = AsyncMock(return_value={'accepted': True})
|
|
monkeypatch.setattr(updates, 'command', command)
|
|
app = FastAPI()
|
|
app.include_router(updates.router, prefix='/system-updates')
|
|
user = SimpleNamespace(id=owner, role=SimpleNamespace(permissions=[SimpleNamespace(name='super_admin')]))
|
|
app.dependency_overrides[get_current_user] = lambda: user
|
|
return TestClient(app), user, command
|
|
|
|
|
|
def test_owner_can_check_and_queue_only_a_valid_revision(setup):
|
|
client, user, command = setup
|
|
assert client.get('/system-updates').json()['update_available']
|
|
assert client.post('/system-updates/check').status_code == 202
|
|
assert client.post('/system-updates/apply', json={'revision': 'b' * 40}).status_code == 202
|
|
command.assert_awaited_with('request', '--revision', 'b' * 40, '--actor', user.id)
|
|
assert client.post('/system-updates/apply', json={'revision': 'main; echo unsafe'}).status_code == 422
|
|
|
|
|
|
def test_other_organization_admin_cannot_deploy_or_read_state(setup):
|
|
client, user, command = setup
|
|
user.id = str(uuid4())
|
|
assert client.get('/system-updates').json() == {'configured': True, 'can_manage': False}
|
|
assert client.post('/system-updates/check').status_code == 403
|
|
assert client.post('/system-updates/apply', json={'revision': 'b' * 40}).status_code == 403
|
|
command.assert_not_awaited()
|
|
|
|
|
|
def test_allowlisted_account_still_needs_super_admin(setup):
|
|
client, user, command = setup
|
|
user.role.permissions = [SimpleNamespace(name='manage_organization')]
|
|
assert client.post('/system-updates/check').status_code == 403
|
|
command.assert_not_awaited()
|