test(auth): add test_existing_endpoints_require_auth + per-test AUTH_DISABLED flips

- New test_existing_endpoints_require_auth.py: spot-check that existing
  /api/* endpoints now require auth (gated via Depends(matrix_gate)) when
  AUTH_DISABLED is False. Health remains public.

- conftest.py: flip AUTH_DISABLED=True for the suite so the legacy
  pre-auth tests keep passing without login. Auth tests flip it back
  off via their own autouse fixture (now patched to use monkeypatch
  for cleanup).

Verified: 53 auth tests pass; 222 pre-existing non-auth failures are
unchanged.
This commit is contained in:
Nora
2026-06-22 15:59:08 -06:00
parent 35e0f5a422
commit 8fc3d9adda
7 changed files with 107 additions and 5 deletions
@@ -0,0 +1,70 @@
"""Spot-check that existing endpoints now require auth (when AUTH_DISABLED is not set).
The conftest in ``tests/conftest.py`` flips ``AUTH_DISABLED=True`` for
every test module that does NOT start with ``test_auth`` — this module
deliberately is NOT named ``test_auth_*`` so it inherits the default
disabled posture... wait, that's the opposite of what we want.
This module is named ``test_existing_endpoints_require_auth`` so the
conftest will treat it as a legacy test and set ``AUTH_DISABLED=True``,
bypassing the auth check entirely. To actually verify the gate, this
test's ``client`` fixture flips ``AUTH_DISABLED`` to ``False``
*just for this test*, then restores it afterwards. This way the
rest of the suite still sees the disabled posture and existing
tests keep passing.
"""
from __future__ import annotations
import pytest
from fastapi.testclient import TestClient
from sqlalchemy import delete
from cyclone.api import app
from cyclone.auth import deps as _auth_deps
from cyclone.auth.deps import AUTH_DISABLED
from cyclone.db import Session as DbSession
from cyclone.db import SessionLocal, User
@pytest.fixture(autouse=True)
def _clear():
with SessionLocal()() as db:
db.execute(delete(DbSession))
db.execute(delete(User))
db.commit()
yield
with SessionLocal()() as db:
db.execute(delete(DbSession))
db.execute(delete(User))
db.commit()
@pytest.fixture
def client():
# Force AUTH_DISABLED=False for these tests so the dep actually checks the cookie.
original = AUTH_DISABLED
_auth_deps.AUTH_DISABLED = False
try:
yield TestClient(app)
finally:
_auth_deps.AUTH_DISABLED = original
@pytest.mark.parametrize("method,path", [
("GET", "/api/claims"),
("GET", "/api/remittances"),
("GET", "/api/providers"),
("GET", "/api/batches"),
("GET", "/api/payers/p1/summary"),
("GET", "/api/activity"),
])
def test_existing_get_endpoints_require_auth(client, method, path):
resp = client.request(method, path)
assert resp.status_code == 401, f"{method} {path} returned {resp.status_code}"
def test_health_is_public(client):
"""``/api/health`` is the public healthcheck and must remain reachable."""
resp = client.get("/api/health")
assert resp.status_code != 401, f"/api/health returned {resp.status_code}"