kin: BATON-SEC-003-backend_dev
This commit is contained in:
parent
097b7af949
commit
f17ee79edb
13 changed files with 593 additions and 125 deletions
|
|
@ -9,6 +9,10 @@ Acceptance criteria:
|
|||
5. Удаление — пользователь исчезает из GET /admin/users, возвращается 204
|
||||
6. Защита: неавторизованный запрос к /admin/* возвращает 401
|
||||
7. Отсутствие регрессии с основным функционалом
|
||||
|
||||
BATON-SEC-003: POST /api/signal now requires Authorization: Bearer <api_key>.
|
||||
Tests 3 and 4 (block/unblock + signal) use /api/register to obtain an api_key,
|
||||
then admin block/unblock the user by their DB id.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
|
|
@ -33,6 +37,11 @@ NGINX_CONF = PROJECT_ROOT / "nginx" / "baton.conf"
|
|||
ADMIN_HEADERS = {"Authorization": "Bearer test-admin-token"}
|
||||
WRONG_HEADERS = {"Authorization": "Bearer wrong-token"}
|
||||
|
||||
# Valid UUID v4 for signal-related tests (registered via /api/register)
|
||||
_UUID_BLOCK = "f0000001-0000-4000-8000-000000000001"
|
||||
_UUID_UNBLOCK = "f0000002-0000-4000-8000-000000000002"
|
||||
_UUID_SIG_OK = "f0000003-0000-4000-8000-000000000003"
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Criterion 6 — Unauthorised requests to /admin/* return 401
|
||||
|
|
@ -250,23 +259,32 @@ async def test_admin_block_user_returns_is_blocked_true() -> None:
|
|||
async def test_admin_block_user_prevents_signal() -> None:
|
||||
"""Заблокированный пользователь не может отправить сигнал — /api/signal возвращает 403."""
|
||||
async with make_app_client() as client:
|
||||
create_resp = await client.post(
|
||||
"/admin/users",
|
||||
json={"uuid": "block-uuid-002", "name": "BlockSignalUser"},
|
||||
headers=ADMIN_HEADERS,
|
||||
# Регистрируем через /api/register чтобы получить api_key
|
||||
reg_resp = await client.post(
|
||||
"/api/register",
|
||||
json={"uuid": _UUID_BLOCK, "name": "BlockSignalUser"},
|
||||
)
|
||||
user_id = create_resp.json()["id"]
|
||||
user_uuid = create_resp.json()["uuid"]
|
||||
assert reg_resp.status_code == 200
|
||||
api_key = reg_resp.json()["api_key"]
|
||||
user_uuid = reg_resp.json()["uuid"]
|
||||
|
||||
# Находим ID пользователя
|
||||
users_resp = await client.get("/admin/users", headers=ADMIN_HEADERS)
|
||||
user = next(u for u in users_resp.json() if u["uuid"] == user_uuid)
|
||||
user_id = user["id"]
|
||||
|
||||
# Блокируем
|
||||
await client.put(
|
||||
f"/admin/users/{user_id}/block",
|
||||
json={"is_blocked": True},
|
||||
headers=ADMIN_HEADERS,
|
||||
)
|
||||
|
||||
# Заблокированный пользователь должен получить 403
|
||||
signal_resp = await client.post(
|
||||
"/api/signal",
|
||||
json={"user_id": user_uuid, "timestamp": 1700000000000, "geo": None},
|
||||
headers={"Authorization": f"Bearer {api_key}"},
|
||||
)
|
||||
assert signal_resp.status_code == 403
|
||||
|
||||
|
|
@ -318,13 +336,19 @@ async def test_admin_unblock_user_returns_is_blocked_false() -> None:
|
|||
async def test_admin_unblock_user_restores_signal_access() -> None:
|
||||
"""После разблокировки пользователь снова может отправить сигнал (200)."""
|
||||
async with make_app_client() as client:
|
||||
create_resp = await client.post(
|
||||
"/admin/users",
|
||||
json={"uuid": "unblock-uuid-002", "name": "UnblockSignalUser"},
|
||||
headers=ADMIN_HEADERS,
|
||||
# Регистрируем через /api/register чтобы получить api_key
|
||||
reg_resp = await client.post(
|
||||
"/api/register",
|
||||
json={"uuid": _UUID_UNBLOCK, "name": "UnblockSignalUser"},
|
||||
)
|
||||
user_id = create_resp.json()["id"]
|
||||
user_uuid = create_resp.json()["uuid"]
|
||||
assert reg_resp.status_code == 200
|
||||
api_key = reg_resp.json()["api_key"]
|
||||
user_uuid = reg_resp.json()["uuid"]
|
||||
|
||||
# Находим ID
|
||||
users_resp = await client.get("/admin/users", headers=ADMIN_HEADERS)
|
||||
user = next(u for u in users_resp.json() if u["uuid"] == user_uuid)
|
||||
user_id = user["id"]
|
||||
|
||||
# Блокируем
|
||||
await client.put(
|
||||
|
|
@ -344,6 +368,7 @@ async def test_admin_unblock_user_restores_signal_access() -> None:
|
|||
signal_resp = await client.post(
|
||||
"/api/signal",
|
||||
json={"user_id": user_uuid, "timestamp": 1700000000000, "geo": None},
|
||||
headers={"Authorization": f"Bearer {api_key}"},
|
||||
)
|
||||
assert signal_resp.status_code == 200
|
||||
assert signal_resp.json()["status"] == "ok"
|
||||
|
|
@ -462,26 +487,28 @@ async def test_register_not_broken_after_admin_operations() -> None:
|
|||
# Основной функционал
|
||||
resp = await client.post(
|
||||
"/api/register",
|
||||
json={"uuid": "regress-user-uuid-001", "name": "RegularUser"},
|
||||
json={"uuid": _UUID_SIG_OK, "name": "RegularUser"},
|
||||
)
|
||||
assert resp.status_code == 200
|
||||
assert resp.json()["uuid"] == "regress-user-uuid-001"
|
||||
assert resp.json()["uuid"] == _UUID_SIG_OK
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_signal_from_unblocked_user_succeeds() -> None:
|
||||
"""Незаблокированный пользователь, созданный через admin API, может отправить сигнал."""
|
||||
async def test_signal_from_registered_unblocked_user_succeeds() -> None:
|
||||
"""Зарегистрированный незаблокированный пользователь может отправить сигнал."""
|
||||
async with make_app_client() as client:
|
||||
create_resp = await client.post(
|
||||
"/admin/users",
|
||||
json={"uuid": "regress-signal-uuid-001", "name": "SignalUser"},
|
||||
headers=ADMIN_HEADERS,
|
||||
reg_resp = await client.post(
|
||||
"/api/register",
|
||||
json={"uuid": _UUID_SIG_OK, "name": "SignalUser"},
|
||||
)
|
||||
user_uuid = create_resp.json()["uuid"]
|
||||
assert reg_resp.status_code == 200
|
||||
api_key = reg_resp.json()["api_key"]
|
||||
user_uuid = reg_resp.json()["uuid"]
|
||||
|
||||
signal_resp = await client.post(
|
||||
"/api/signal",
|
||||
json={"user_id": user_uuid, "timestamp": 1700000000000, "geo": None},
|
||||
headers={"Authorization": f"Bearer {api_key}"},
|
||||
)
|
||||
assert signal_resp.status_code == 200
|
||||
assert signal_resp.json()["status"] == "ok"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue