"""Basic auth + fail-closed behaviour (audit C2).""" import base64 from fastapi.testclient import TestClient import app.main as main def _basic(user: str, password: str) -> dict: raw = base64.b64encode(f"{user}:{password}".encode()).decode() return {"Authorization": f"Basic {raw}"} def test_no_credentials_means_open_but_health_works(client): assert client.get("/").status_code == 200 def test_auth_required_when_configured(monkeypatch, fake_gitea): monkeypatch.setenv("KANBANTE_AUTH_USER", "bruno") monkeypatch.setenv("KANBANTE_AUTH_PASSWORD", "motdepasse") with TestClient(main.app) as client: # Sans en-tête navigateur : 401 (comportement historique). assert client.get("/").status_code == 401 # Le Basic reste accepté pour les scripts (0.22.0). assert client.get("/", headers=_basic("bruno", "mauvais")).status_code == 401 assert client.get("/", headers=_basic("bruno", "motdepasse")).status_code == 200 # Un navigateur, lui, est envoyé vers l'écran de connexion. r = client.get( "/", headers={"Accept": "text/html"}, follow_redirects=False ) assert r.status_code == 303 assert r.headers["location"].startswith("/login") # Liveness stays public for Docker HEALTHCHECK. assert client.get("/api/health").status_code == 200 def test_require_auth_fails_closed_without_credentials(monkeypatch, fake_gitea): monkeypatch.delenv("KANBANTE_AUTH_USER", raising=False) monkeypatch.delenv("KANBANTE_AUTH_PASSWORD", raising=False) monkeypatch.setenv("KANBANTE_REQUIRE_AUTH", "1") with TestClient(main.app) as client: assert client.get("/").status_code == 503 assert client.get("/api/health").status_code == 200