# tests/test_operator_gate.py import uuid from tests.conftest import wire_operator_auth from backend.models import OperatorUser from backend.operator_auth import make_operator_cookie, COOKIE_NAME from backend.auth_passwords import hash_password def _make_user(db, role="admin", **kw): u = OperatorUser(id=str(uuid.uuid4()), email=kw.pop("email", "u@x.com"), display_name="U", password_hash=hash_password("pw"), role=role, **kw) db.add(u) db.commit() return u def test_flag_off_passes_everything(client, db_session, monkeypatch): wire_operator_auth(monkeypatch, db_session, enabled=False) assert client.get("/", follow_redirects=False).status_code == 200 def test_gated_html_redirects_to_login_when_unauth(client, db_session, monkeypatch): wire_operator_auth(monkeypatch, db_session, enabled=True) r = client.get("/", follow_redirects=False) assert r.status_code == 303 assert r.headers["location"].startswith("/login?next=") def test_gated_api_returns_401_json_when_unauth(client, db_session, monkeypatch): wire_operator_auth(monkeypatch, db_session, enabled=True) r = client.get("/api/status-snapshot", follow_redirects=False) assert r.status_code == 401 def test_valid_session_passes(client, db_session, monkeypatch): u = _make_user(db_session) wire_operator_auth(monkeypatch, db_session, enabled=True) client.cookies.set(COOKIE_NAME, make_operator_cookie(u.id)) assert client.get("/", follow_redirects=False).status_code == 200 def test_must_change_password_user_routed_to_change_password(client, db_session, monkeypatch): u = _make_user(db_session, must_change_password=True) wire_operator_auth(monkeypatch, db_session, enabled=True) client.cookies.set(COOKIE_NAME, make_operator_cookie(u.id)) r = client.get("/", follow_redirects=False) assert r.status_code == 303 assert r.headers["location"] == "/change-password" def test_exempt_paths_pass_without_cookie(client, db_session, monkeypatch): wire_operator_auth(monkeypatch, db_session, enabled=True) assert client.get("/health", follow_redirects=False).status_code == 200 def test_portal_paths_are_exempt(client, db_session, monkeypatch): wire_operator_auth(monkeypatch, db_session, enabled=True) # /portal/p/ hits the portal's own gate (403/404), never the operator login. r = client.get("/portal/p/nope", follow_redirects=False) assert r.status_code in (403, 404) def test_must_change_user_on_api_gets_403_json_not_redirect(client, db_session, monkeypatch): u = _make_user(db_session, must_change_password=True) wire_operator_auth(monkeypatch, db_session, enabled=True) client.cookies.set(COOKIE_NAME, make_operator_cookie(u.id)) r = client.get("/api/status-snapshot", follow_redirects=False) assert r.status_code == 403 assert r.json()["detail"] == "Password change required"