from __future__ import annotations from types import SimpleNamespace from ariadne.services import oauth2_proxy as oauth_module from ariadne.services.oauth2_proxy import OAuth2ProxyService, _oauth_client_payload, _valid_cookie_secret def test_oauth_client_payload() -> None: payload = _oauth_client_payload("wolf", "https://wolf.bstein.dev") assert payload["clientId"] == "wolf" assert payload["redirectUris"] == ["https://wolf.bstein.dev/oauth2/callback"] def test_valid_cookie_secret() -> None: assert _valid_cookie_secret("x" * 32) == "x" * 32 assert _valid_cookie_secret("short") == "" assert _valid_cookie_secret(None) == "" def test_ensure_wolf_creates_client_and_writes_vault(monkeypatch) -> None: monkeypatch.setattr( oauth_module, "settings", SimpleNamespace(wolf_oidc_client_id="wolf", wolf_oidc_base_url="https://wolf.bstein.dev", wolf_oidc_vault_path="game-stream/wolf-oidc"), ) calls: list[str] = [] written = {} class DummyKeycloak: def __init__(self) -> None: self.created = False def ready(self): return True def find_client(self, client_id): return {"id": "client-uuid", "clientId": client_id} if self.created else None def create_client(self, _payload): self.created = True calls.append("create") def update_client(self, _client_uuid, _payload): calls.append("update") def find_client_scope_id(self, _name): return "scope-uuid" def attach_optional_client_scope(self, _client_uuid, _scope_id): calls.append("scope") def get_client_secret(self, _client_uuid): return "client-secret" class DummyVault: def read_kv_secret(self, _path): return {"cookie_secret": "a" * 32} def write_kv_secret(self, path, data): written["path"] = path written["data"] = data monkeypatch.setattr(oauth_module, "keycloak_admin", DummyKeycloak()) monkeypatch.setattr(oauth_module, "vault", DummyVault()) assert OAuth2ProxyService().ensure_wolf()["status"] == "ok" assert calls == ["create", "update", "scope"] assert written["data"]["client_secret"] == "client-secret" assert written["data"]["cookie_secret"] == "a" * 32 def test_ensure_wolf_reports_missing_keycloak(monkeypatch) -> None: monkeypatch.setattr( oauth_module, "settings", SimpleNamespace(wolf_oidc_client_id="wolf", wolf_oidc_base_url="https://wolf.bstein.dev", wolf_oidc_vault_path="game-stream/wolf-oidc"), ) monkeypatch.setattr(oauth_module, "keycloak_admin", SimpleNamespace(ready=lambda: False)) assert OAuth2ProxyService().ensure_wolf()["status"] == "error" def test_ensure_wolf_rejects_missing_client_after_create(monkeypatch) -> None: monkeypatch.setattr( oauth_module, "settings", SimpleNamespace(wolf_oidc_client_id="wolf", wolf_oidc_base_url="https://wolf.bstein.dev", wolf_oidc_vault_path="game-stream/wolf-oidc"), ) monkeypatch.setattr( oauth_module, "keycloak_admin", SimpleNamespace(ready=lambda: True, find_client=lambda _client_id: None, create_client=lambda _payload: None), ) try: OAuth2ProxyService().ensure_wolf() except RuntimeError as exc: assert "not found" in str(exc) else: raise AssertionError("missing client should fail") def test_ensure_wolf_rejects_missing_client_uuid(monkeypatch) -> None: monkeypatch.setattr( oauth_module, "settings", SimpleNamespace(wolf_oidc_client_id="wolf", wolf_oidc_base_url="https://wolf.bstein.dev", wolf_oidc_vault_path="game-stream/wolf-oidc"), ) monkeypatch.setattr( oauth_module, "keycloak_admin", SimpleNamespace(ready=lambda: True, find_client=lambda _client_id: {"id": ""}, create_client=lambda _payload: None), ) try: OAuth2ProxyService().ensure_sunshine() except RuntimeError as exc: assert "id missing" in str(exc) else: raise AssertionError("missing client id should fail")