fix(auth): hide /admin/users when flag off; pass OPTIONS preflight through gate
- operator_users router now depends on _require_auth_enabled, which raises 404 when OPERATOR_AUTH_ENABLED is false — prevents world-open pre-seeding of a superadmin while the flag is off (the default). Flag is read as a live module attribute (operator_auth.OPERATOR_AUTH_ENABLED) so monkeypatching in tests and a runtime flip both take effect. - operator_gate passes OPTIONS requests through immediately before the exempt- path check, so CORS preflight reaches CORSMiddleware rather than being 303/401'd by the gate. - Two new tests: test_admin_surface_404s_when_flag_off (test_operator_users) and test_options_preflight_passes_through_gate (test_operator_gate). Full suite: 90 passed. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -67,3 +67,10 @@ def test_must_change_user_on_api_gets_403_json_not_redirect(client, db_session,
|
||||
r = client.get("/api/status-snapshot", follow_redirects=False)
|
||||
assert r.status_code == 403
|
||||
assert r.json()["detail"] == "Password change required"
|
||||
|
||||
|
||||
def test_options_preflight_passes_through_gate(client, db_session, monkeypatch):
|
||||
wire_operator_auth(monkeypatch, db_session, enabled=True)
|
||||
# CORS preflight has no cookie; the gate must not 303/401 it.
|
||||
r = client.options("/api/status-snapshot", follow_redirects=False)
|
||||
assert r.status_code not in (303, 401)
|
||||
|
||||
@@ -118,3 +118,15 @@ def test_deferred_operator_role_rejected_by_api(client, db_session, monkeypatch)
|
||||
_login_as(client, su)
|
||||
assert client.post("/api/admin/users", json={"email": "op@x.com", "name": "Op", "role": "operator"}).status_code == 400
|
||||
assert client.post(f"/api/admin/users/{target.id}/role", json={"role": "operator"}).status_code == 400
|
||||
|
||||
|
||||
def test_admin_surface_404s_when_flag_off(client, db_session, monkeypatch):
|
||||
su, _ = create_operator(db_session, "su@x.com", "Su", "superadmin", password="pw-123456")
|
||||
wire_operator_auth(monkeypatch, db_session, enabled=False)
|
||||
_login_as(client, su)
|
||||
# With operator auth OFF, the management surface must not exist (404), even
|
||||
# though require_role passes through — otherwise it'd be world-open.
|
||||
assert client.get("/admin/users").status_code == 404
|
||||
assert client.get("/api/admin/users").status_code == 404
|
||||
assert client.post("/api/admin/users",
|
||||
json={"email": "x@x.com", "name": "X", "role": "admin"}).status_code == 404
|
||||
|
||||
Reference in New Issue
Block a user