"""Flask routes: health, CORS, portal auth fail-closed, roster auth.""" from unittest.mock import patch import pytest from server.app import create_app @pytest.fixture def client(): app = create_app() app.testing = True return app.test_client() def test_health_reports_stage_and_sha(client, monkeypatch): monkeypatch.setenv("STAGE", "dev") monkeypatch.setenv("GIT_SHA", "abc123") response = client.get("/api/health") assert response.status_code == 200 assert response.get_json() == {"stage": "dev", "sha": "abc123"} def test_portal_options_is_204_with_cors(client): response = client.options( "/api/shifts", headers={"Origin": "https://internal.seahaven.com"}, ) assert response.status_code == 204 assert ( response.headers["Access-Control-Allow-Origin"] == "https://internal.seahaven.com" ) def test_portal_unknown_origin_has_no_acao(client): response = client.options( "/api/shifts", headers={"Origin": "https://evil.example"}, ) assert response.status_code == 204 assert "Access-Control-Allow-Origin" not in response.headers def test_portal_missing_bearer_is_401(client): response = client.get("/api/shifts") assert response.status_code == 401 body = response.get_json() assert body["error"]["code"] == "UNAUTHORIZED" def test_portal_invalid_token_is_401(client): with patch( "shared.portal_http.verify_cognito_id_token", return_value=None, ): response = client.get( "/api/shifts", headers={"Authorization": "Bearer nope"}, ) assert response.status_code == 401 def test_roster_missing_bearer_is_401(client, monkeypatch): monkeypatch.setenv( "ROSTER_API_TOKEN_SECRET", "afterhours-shift-manager/roster-api-token" ) with patch("shared.roster_http.get_secret", return_value="expected"): response = client.put( "/roster", json={"name": "Pat", "extension": "110", "slack_user_id": "U1"} ) assert response.status_code == 401 def test_roster_wrong_token_is_401(client, monkeypatch): monkeypatch.setenv( "ROSTER_API_TOKEN_SECRET", "afterhours-shift-manager/roster-api-token" ) import shared.roster_http as roster_http roster_http._cached_token = None with patch("shared.roster_http.get_secret", return_value="expected"): response = client.put( "/roster", headers={"Authorization": "Bearer nope"}, json={"name": "Pat", "extension": "110", "slack_user_id": "UABC"}, ) assert response.status_code == 401