mirror of
https://github.com/Sea-Haven-Industries/afterhours-shift-manager.git
synced 2026-09-30 04:33:10 +00:00
fix(portal-api): keep CORS headers on unexpected 500s
Portal SPA error handling needs Access-Control-Allow-Origin even when DynamoDB or other internals fail, otherwise the browser hides the 500.
This commit is contained in:
parent
7c5d44e9cf
commit
5b272f9b4a
4 changed files with 51 additions and 3 deletions
|
|
@ -6,7 +6,7 @@ import base64
|
|||
import logging
|
||||
|
||||
import shared.sentry_init # noqa: F401
|
||||
from shared.portal_http import encode_body, handle
|
||||
from shared.portal_http import cors_headers, encode_body, handle
|
||||
from shared.portal_ops import ActionError
|
||||
|
||||
logger = logging.getLogger()
|
||||
|
|
@ -79,14 +79,14 @@ def handler(event, context):
|
|||
logger.exception("portal api action error")
|
||||
return {
|
||||
"statusCode": exc.status,
|
||||
"headers": {"Content-Type": "application/json"},
|
||||
"headers": cors_headers(_header(event, "origin")),
|
||||
"body": encode_body({"error": {"code": exc.code, "message": exc.message}}),
|
||||
}
|
||||
except Exception:
|
||||
logger.exception("portal api unexpected failure")
|
||||
return {
|
||||
"statusCode": 500,
|
||||
"headers": {"Content-Type": "application/json"},
|
||||
"headers": cors_headers(_header(event, "origin")),
|
||||
"body": encode_body(
|
||||
{"error": {"code": "INTERNAL", "message": "Internal error"}}
|
||||
),
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import logging
|
||||
from decimal import Decimal
|
||||
from typing import Any
|
||||
from urllib.parse import unquote
|
||||
|
|
@ -12,6 +13,8 @@ from shared.portal_ops import ActionError, snapshot
|
|||
from shared.schedule import ShiftSchedule
|
||||
from shared import portal_ops as ops
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
CORS_ORIGINS = {
|
||||
"https://internal.seahaven.com",
|
||||
"https://internal.dev.seahaven.com",
|
||||
|
|
@ -210,3 +213,10 @@ def handle(
|
|||
headers,
|
||||
{"error": {"code": exc.code, "message": exc.message}},
|
||||
)
|
||||
except Exception:
|
||||
logger.exception("portal http unexpected failure")
|
||||
return (
|
||||
500,
|
||||
headers,
|
||||
{"error": {"code": "INTERNAL", "message": "Internal error"}},
|
||||
)
|
||||
|
|
|
|||
|
|
@ -85,3 +85,17 @@ def test_cors_header_for_portal_origin(portalapi_app, schedule, identity):
|
|||
result["headers"]["Access-Control-Allow-Origin"]
|
||||
== "https://internal.seahaven.com"
|
||||
)
|
||||
|
||||
|
||||
def test_unexpected_failure_keeps_cors(portalapi_app, identity, monkeypatch):
|
||||
monkeypatch.setattr(
|
||||
"shared.portal_http.ShiftSchedule",
|
||||
lambda: (_ for _ in ()).throw(RuntimeError("ddb down")),
|
||||
)
|
||||
result = portalapi_app.handler(_event(origin="https://internal.seahaven.com"), None)
|
||||
assert result["statusCode"] == 500
|
||||
assert (
|
||||
result["headers"]["Access-Control-Allow-Origin"]
|
||||
== "https://internal.seahaven.com"
|
||||
)
|
||||
assert json.loads(result["body"])["error"]["code"] == "INTERNAL"
|
||||
|
|
|
|||
|
|
@ -50,6 +50,30 @@ def test_portal_missing_bearer_is_401(client):
|
|||
assert body["error"]["code"] == "UNAUTHORIZED"
|
||||
|
||||
|
||||
def test_portal_unexpected_failure_keeps_cors(client):
|
||||
with patch(
|
||||
"shared.portal_http.verify_cognito_id_token",
|
||||
return_value={"name": "Alice", "email": "alice@seahavenind.com"},
|
||||
):
|
||||
with patch(
|
||||
"shared.portal_http.ShiftSchedule",
|
||||
side_effect=RuntimeError("ddb down"),
|
||||
):
|
||||
response = client.get(
|
||||
"/api/shifts",
|
||||
headers={
|
||||
"Authorization": "Bearer token",
|
||||
"Origin": "https://internal.seahaven.com",
|
||||
},
|
||||
)
|
||||
assert response.status_code == 500
|
||||
assert (
|
||||
response.headers["Access-Control-Allow-Origin"]
|
||||
== "https://internal.seahaven.com"
|
||||
)
|
||||
assert response.get_json()["error"]["code"] == "INTERNAL"
|
||||
|
||||
|
||||
def test_portal_invalid_token_is_401(client):
|
||||
with patch(
|
||||
"shared.portal_http.verify_cognito_id_token",
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue