kin: BATON-SEC-003-backend_dev

This commit is contained in:
Gros Frumos 2026-03-21 08:12:01 +02:00
parent 097b7af949
commit f17ee79edb
13 changed files with 593 additions and 125 deletions

View file

@ -11,6 +11,9 @@ Acceptance criteria:
6. POST /api/register возвращает 200 (FastAPI-маршрут не сломан).
7. POST /api/signal возвращает 200 (FastAPI-маршрут не сломан).
8. POST /api/webhook/telegram возвращает 200 с корректным секретом.
BATON-SEC-003: POST /api/signal now requires Authorization: Bearer <api_key>.
UUID constants satisfy the UUID v4 pattern.
"""
from __future__ import annotations
@ -23,6 +26,7 @@ os.environ.setdefault("CHAT_ID", "-1001234567890")
os.environ.setdefault("WEBHOOK_SECRET", "test-webhook-secret")
os.environ.setdefault("WEBHOOK_URL", "https://example.com/api/webhook/telegram")
os.environ.setdefault("FRONTEND_ORIGIN", "http://localhost:3000")
os.environ.setdefault("ADMIN_TOKEN", "test-admin-token")
import pytest
@ -31,6 +35,10 @@ from tests.conftest import make_app_client
PROJECT_ROOT = Path(__file__).parent.parent
NGINX_CONF = PROJECT_ROOT / "nginx" / "baton.conf"
# Valid UUID v4 constants
_UUID_REG = "e0000001-0000-4000-8000-000000000001"
_UUID_SIG = "e0000002-0000-4000-8000-000000000002"
# ---------------------------------------------------------------------------
# Criterion 1 — location /api/ proxies to FastAPI
# ---------------------------------------------------------------------------
@ -52,7 +60,6 @@ def test_nginx_conf_has_api_location_block() -> None:
def test_nginx_conf_api_location_proxies_to_fastapi() -> None:
"""Блок location /api/ должен делать proxy_pass на 127.0.0.1:8000."""
content = NGINX_CONF.read_text(encoding="utf-8")
# Ищем блок api и proxy_pass внутри
api_block = re.search(
r"location\s+/api/\s*\{([^}]+)\}", content, re.DOTALL
)
@ -95,7 +102,6 @@ def test_nginx_conf_health_location_proxies_to_fastapi() -> None:
def test_nginx_conf_root_location_has_root_directive() -> None:
"""location / в nginx.conf должен содержать директиву root (статика)."""
content = NGINX_CONF.read_text(encoding="utf-8")
# Ищем последний блок location / (не /api/, не /health)
root_block = re.search(
r"location\s+/\s*\{([^}]+)\}", content, re.DOTALL
)
@ -179,13 +185,14 @@ async def test_api_register_not_broken_after_nginx_change() -> None:
async with make_app_client() as client:
response = await client.post(
"/api/register",
json={"uuid": "baton-006-uuid-001", "name": "TestUser"},
json={"uuid": _UUID_REG, "name": "TestUser"},
)
assert response.status_code == 200
data = response.json()
assert data["user_id"] > 0
assert data["uuid"] == "baton-006-uuid-001"
assert data["uuid"] == _UUID_REG
assert "api_key" in data
# ---------------------------------------------------------------------------
@ -197,19 +204,21 @@ async def test_api_register_not_broken_after_nginx_change() -> None:
async def test_api_signal_not_broken_after_nginx_change() -> None:
"""POST /api/signal должен вернуть 200 — функция не сломана изменением nginx."""
async with make_app_client() as client:
# Сначала регистрируем пользователя
await client.post(
reg_resp = await client.post(
"/api/register",
json={"uuid": "baton-006-uuid-002", "name": "SignalUser"},
json={"uuid": _UUID_SIG, "name": "SignalUser"},
)
# Отправляем сигнал
assert reg_resp.status_code == 200
api_key = reg_resp.json()["api_key"]
response = await client.post(
"/api/signal",
json={
"user_id": "baton-006-uuid-002",
"user_id": _UUID_SIG,
"timestamp": 1700000000000,
"geo": None,
},
headers={"Authorization": f"Bearer {api_key}"},
)
assert response.status_code == 200