test(rbac): test-mode bypass so api/v1 suite can authenticate (CI-rehab 1/3)
The whole backend api/v1 test suite hits `app` via TestClient mimo Caddy, so rbac_guard (app/main.py) 401'd every authed request (no X-Authenticated-User) — 112 tests red, the suite effectively dead (which is how #994's district 500 shipped uncaught). Add `settings.testing` (default False — prod RBAC untouched) + a strictly-gated bypass at the top of rbac_guard; tests/conftest.py enables it (env TESTING=1 + settings.testing=True before app import). Security: bypass fires ONLY when settings.testing is True, which is set NOWHERE in prod (default False; only tests/conftest.py flips it). RBAC's 401/403 logic stays covered by tests/test_rbac.py (its own middleware copy, ignores the flag). Effect: 112 → 42 failed, 1590 → 1660 passed. Remaining 42 (+5 mv_layout env errors) are stale-mock/assertion drift + env-required tests — fixed in CI-rehab 2/3. Foundation for a real Forgejo pytest gate (3/3). Refs #944.
This commit is contained in:
parent
c8ab3e8be9
commit
0247f13fb6
3 changed files with 23 additions and 0 deletions
|
|
@ -17,6 +17,10 @@ class Settings(BaseSettings):
|
||||||
glitchtip_dsn: str | None = None
|
glitchtip_dsn: str | None = None
|
||||||
glitchtip_traces_sample_rate: float = 0.05
|
glitchtip_traces_sample_rate: float = 0.05
|
||||||
environment: str = "dev"
|
environment: str = "dev"
|
||||||
|
# Test-mode flag (env TESTING=1). СТРОГО default False — в проде RBAC-гейт
|
||||||
|
# (app/main.py rbac_guard) активен. True только в pytest (tests/conftest.py),
|
||||||
|
# где запросы идут по app мимо Caddy и не несут X-Authenticated-User.
|
||||||
|
testing: bool = False
|
||||||
|
|
||||||
@model_validator(mode="after")
|
@model_validator(mode="after")
|
||||||
def _promote_legacy_sentry_dsn(self) -> "Settings":
|
def _promote_legacy_sentry_dsn(self) -> "Settings":
|
||||||
|
|
|
||||||
|
|
@ -97,6 +97,12 @@ async def rbac_guard(
|
||||||
request: Request,
|
request: Request,
|
||||||
call_next: Callable[[Request], Awaitable[Response]],
|
call_next: Callable[[Request], Awaitable[Response]],
|
||||||
) -> Response:
|
) -> Response:
|
||||||
|
# Test-mode bypass: pytest бьёт по app мимо Caddy → нет X-Authenticated-User.
|
||||||
|
# СТРОГО gated на settings.testing (default False) — прод RBAC не затронут.
|
||||||
|
# RBAC-логика покрыта отдельно в tests/test_rbac.py (своя копия middleware).
|
||||||
|
if settings.testing:
|
||||||
|
return await call_next(request)
|
||||||
|
|
||||||
path = request.url.path
|
path = request.url.path
|
||||||
if path in _PUBLIC_PATHS:
|
if path in _PUBLIC_PATHS:
|
||||||
return await call_next(request)
|
return await call_next(request)
|
||||||
|
|
|
||||||
|
|
@ -9,8 +9,21 @@ NB: RBAC-гейт (app/main.py `rbac_guard`) требует заголовок `
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
# Включаем test-mode ДО любого импорта app: rbac_guard (app/main.py) пропускает
|
||||||
|
# запросы при settings.testing=True (юнит-тесты бьют по app мимо Caddy и не несут
|
||||||
|
# X-Authenticated-User → иначе 401 на всём api/v1). Ставим и env (на случай
|
||||||
|
# ре-инстанцирования Settings), и атрибут синглтона напрямую (надёжно независимо
|
||||||
|
# от порядка импортов). RBAC-логика (401/403) покрыта в test_rbac.py — там своя
|
||||||
|
# копия middleware, на settings.testing НЕ смотрит, поэтому остаётся валидной.
|
||||||
|
os.environ.setdefault("TESTING", "1")
|
||||||
|
from app.core.config import settings
|
||||||
|
|
||||||
|
settings.testing = True
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(autouse=True)
|
@pytest.fixture(autouse=True)
|
||||||
def _clear_dependency_overrides():
|
def _clear_dependency_overrides():
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue