fix(dashboard): resolve guest users in Excel export instead of crashing on g.user.id - #43340
Conversation
|
Bito Automatic Review Skipped - Branch Excluded |
✅ Deploy Preview for superset-docs-preview ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## fix/excel-export-guest-sessions-and-s3-link-expiry #43340 +/- ##
=====================================================================================
Coverage ? 66.66%
=====================================================================================
Files ? 2874
Lines ? 163763
Branches ? 37788
=====================================================================================
Hits ? 109178
Misses ? 52455
Partials ? 2130
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
| if user_id is not None: | ||
| user = security_manager.get_user_by_id(user_id) | ||
| elif guest_token: | ||
| user = security_manager.get_guest_user_from_token(guest_token) | ||
| else: | ||
| user = None |
There was a problem hiding this comment.
Suggestion: The guest reconstruction runs before the try/finally that releases the distributed lock. If get_guest_user_from_token raises—for example because the guest role lookup or metadata access fails—the task exits without releasing the lock acquired by the API, leaving every guest export for that dashboard blocked until the TTL expires. Move user reconstruction inside the protected block or explicitly release the lock on this failure path. [missing cleanup]
Severity Level: Major ⚠️
- ❌ Guest exports remain blocked until lock TTL expiry.
- ⚠️ All guests share the affected dashboard's slot-0 lock.
- ⚠️ Failure status is not recorded for this path.Prompt for AI Agent 🤖
This is a comment left during a code review.
**Path:** superset/tasks/export_dashboard_excel.py
**Line:** 479:484
**Comment:**
*Missing Cleanup: The guest reconstruction runs before the `try`/`finally` that releases the distributed lock. If `get_guest_user_from_token` raises—for example because the guest role lookup or metadata access fails—the task exits without releasing the lock acquired by the API, leaving every guest export for that dashboard blocked until the TTL expires. Move user reconstruction inside the protected block or explicitly release the lock on this failure path.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fixThere was a problem hiding this comment.
Good catch, fixed in 619bd26: user resolution now happens inside the protected block, so a failing guest role lookup still releases the lock in the finally and still records a pollable failure status via _handle_export_failure (which tolerates user=None). Added test_lock_released_and_failure_recorded_when_user_resolution_fails covering exactly this path. Note the pre-existing code had the same latent gap with get_user_by_id, which this also closes.
|
The flagged issue is correct. In To resolve this, move the user reconstruction logic inside the superset/tasks/export_dashboard_excel.py |
4ad2fcd to
619bd26
Compare
…ng on g.user.id GuestUser extends AnonymousUserMixin and has no id attribute, so an embedded guest triggering export_xlsx crashed with AttributeError (500 Fatal error) on g.user.id before the task was ever enqueued. Pass user_id=None plus the guest token payload instead, and reconstruct the guest in the worker via get_guest_user_from_token (the async-queries pattern) so the export runs under the token's RLS rules and resource claims rather than an elevated identity. Guests share throttle-lock slot 0 per dashboard, acquired and released with the same key. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012HwFSVNUzsZ4xW6D8Y2n95
619bd26 to
4423f50
Compare
…est access Guest datasource authorization requires form_data.dashboardId to link a chart to the embedded dashboard (raise_for_access). The browser stamps it on every interactive request, but the export task replays saved query contexts that do not carry it, so every chart in a guest export failed the access check and the workbook came back empty. Stamp the exporting dashboard's id the same way the browser does; logged-in exports already carry dashboard scope and are unaffected. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012HwFSVNUzsZ4xW6D8Y2n95
Embedded (iframe) sessions get delivery neutral toast copy (no email promise a guest can never receive), a polling window that outlives the server task budget so a slow but successful export is not orphaned, and the image export item hidden (the webdriver cannot render Explore under a guest identity, so it would burn the whole task budget producing nothing). The pending toast now mirrors the screenshot download's repeating noDuplicate info toast for all sessions. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012HwFSVNUzsZ4xW6D8Y2n95
…s redirect The direct window.location.href assignment from the base branch trips the navigationUtils invariant scan: it bypasses ensureAppRoot (broken under subdirectory deployment) and the scheme guard. Use redirect() instead; tests assert the redirect call rather than the raw sink. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012HwFSVNUzsZ4xW6D8Y2n95
…t toast Customer feedback showed the email-only wording made the export read as an email delivery feature, prompting requests for a direct download that already exists. Promise both channels, matching actual behavior. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012HwFSVNUzsZ4xW6D8Y2n95
SUMMARY
Targets
fix/excel-export-guest-sessions-and-s3-link-expiry(#43336), notmaster. It fixes a bug in that PR's guest path and is meant to merge into it, so the guard removal and this fix travel together.#43336 removes the
isinstance(g.user, GuestUser)guard that returned 400 so embedded guests can export, butexport_xlsxstill callsg.user.id(for the throttle lock params and the Celery task'suser_id).GuestUserextendsAnonymousUserMixinand has noidattribute, so a guest POST crashes withAttributeErrorand returns 500{"message": "Fatal error"}before the task is ever enqueued. Verified empirically on a staging deployment carrying #43336's changes: the embedded export button returned exactly that 500; with this fix applied the export goes through.The fix mirrors
_load_user_from_job_metadatainsuperset/tasks/async_queries.py:user_id=get_user_id()(Nonefor guests) plusguest_token=getattr(g.user, "guest_token", None).security_manager.get_guest_user_from_token(...), so the export runs under the token's RLS rules and resource claims, never under an elevated identity.ADDITIONAL INFORMATION