Follow-up to #43834. That change guarded is_sanitization_required() so a
raising user loader could no longer turn error responses into bare 500s,
but it failed *open*: when the guest-user check raised it returned False
("do not sanitize"), which can disclose raw engine errors to a genuine
embedded guest.
The check can raise for a resolvable guest, not only an unresolvable
anonymous one: get_guest_user_from_token() calls find_role() (a metadata-DB
round trip) outside the request loader's try/except, and is_guest_user()
consults the EMBEDDED_SUPERSET feature hook first. On a request whose DB
session is already broken -- exactly the state a SQLAlchemyError handler
runs in -- a valid guest token then yields the raw driver error instead of
a redacted message.
Make the fallback incapable of raising and fail closed for anyone
presenting a token:
- is_sanitization_required(): on failure, inside a request context fall
back to whether the request carries a guest token (reading the header or
form field cannot raise); redact if it does, leave genuinely anonymous
errors untouched. Outside a request context (Celery worker under
override_user) fail closed and redact, since the payload is delivered to
the embedded viewer. Reworded the docstring as an availability-over-
confidentiality trade-off rather than a definitional truth.
- Resolve the decision once and thread it down: add an optional
`required` param to the sanitize_* helpers so a list is looked up a
single time instead of once per error (fixes the N+1 loader calls and
WARNING log-spam on multi-error responses).
- charts/data/api.py: replace the raw outer is_guest_user() with the
guarded, once-resolved decision and reuse it for both the stacktrace pop
and the message sanitization, so the block can no longer half-redact
(drop the stacktrace while leaking the raw error).
- views/error_handling.py: give the last-resort show_unexpected_exception
the same try/except FileNotFoundError fallback its siblings have, so a
missing 500.html no longer collapses the response to a bare 500 with no
SIP-40 body.
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Elizabeth Thompson <eschutho@gmail.com>