"""The Test button: it exists to tell a working channel from a broken one.""" from typing import Any import pytest from fastapi.testclient import TestClient from fluksio.core.config import settings from fluksio.flow.alerts import AlertsConfig, Channel PREFIX = f"{settings.API_V1_STR}/alerts" def _one_channel(client: TestClient) -> Any: alerts = client.app.state.flow_controller.alerts # type: ignore[attr-defined] alerts.config = AlertsConfig( channels=[Channel(name="phone", kind="ntfy", config={"topic": "t"})] ) return alerts def test_a_channel_that_cannot_deliver_is_not_a_success( client: TestClient, superuser_token_headers: dict[str, str], monkeypatch: pytest.MonkeyPatch, ) -> None: alerts = _one_channel(client) async def refuse(_config: dict[str, Any], _alert: Any) -> None: raise RuntimeError("nobody home") monkeypatch.setattr(alerts, "_send_ntfy", refuse) response = client.post(f"{PREFIX}/test/phone", headers=superuser_token_headers) assert response.status_code == 502 assert "nobody home" in response.json()["detail"] def test_a_channel_that_delivers_says_so( client: TestClient, superuser_token_headers: dict[str, str], monkeypatch: pytest.MonkeyPatch, ) -> None: alerts = _one_channel(client) sent = [] async def accept(_config: dict[str, Any], alert: Any) -> None: sent.append(alert) monkeypatch.setattr(alerts, "_send_ntfy", accept) response = client.post(f"{PREFIX}/test/phone", headers=superuser_token_headers) assert response.status_code == 200 assert len(sent) == 1 def test_an_unknown_channel_is_a_404( client: TestClient, superuser_token_headers: dict[str, str] ) -> None: _one_channel(client) response = client.post(f"{PREFIX}/test/nowhere", headers=superuser_token_headers) assert response.status_code == 404 def test_an_ordinary_account_cannot_read_or_change_the_alert_setup( client: TestClient, normal_user_token_headers: dict[str, str] ) -> None: """Channels hold credential references, topics and urls: a superuser's.""" config = {"channels": [], "rules": []} assert ( client.get(f"{PREFIX}/config", headers=normal_user_token_headers).status_code == 403 ) assert ( client.put( f"{PREFIX}/config", headers=normal_user_token_headers, json=config ).status_code == 403 ) assert ( client.post( f"{PREFIX}/test/phone", headers=normal_user_token_headers ).status_code == 403 ) def test_a_stored_secret_cannot_be_pointed_at_a_host_an_ordinary_account_chose( client: TestClient, superuser_token_headers: dict[str, str], normal_user_token_headers: dict[str, str], monkeypatch: pytest.MonkeyPatch, ) -> None: """An ntfy `server` plus a `$secret` token used to send the secret there.""" import httpx client.put( f"{settings.API_V1_STR}/secrets/vault-token", headers=superuser_token_headers, json={"value": "S3CRET"}, ) reached: list[str] = [] async def post(_self: Any, url: Any, **_kwargs: Any) -> httpx.Response: reached.append(str(url)) return httpx.Response(200, request=httpx.Request("POST", url)) monkeypatch.setattr(httpx.AsyncClient, "post", post) config = { "channels": [ { "name": "x", "kind": "ntfy", "config": { "server": "http://attacker.invalid", "topic": "t", "token": {"$secret": "vault-token"}, }, } ], "rules": [], } client.put(f"{PREFIX}/config", headers=normal_user_token_headers, json=config) client.post(f"{PREFIX}/test/x", headers=normal_user_token_headers) assert reached == [] def test_any_account_can_subscribe_its_own_browser( client: TestClient, normal_user_token_headers: dict[str, str] ) -> None: """Where this device can be reached is not a superuser's to hold.""" response = client.get(f"{PREFIX}/webpush/key", headers=normal_user_token_headers) assert response.status_code == 200 assert response.json()["key"]