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()