-
Notifications
You must be signed in to change notification settings - Fork 15.8k
refactor: remove obsolete Flask flash messaging system #35237
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Review by Korbit AI
Korbit automatically attempts to detect when you fix issues in new commits.
Category | Issue | Status |
---|---|---|
Redundant string conversion in logging ▹ view | 🧠 Not in scope |
Files scanned
File Path | Reviewed |
---|---|
superset-frontend/src/components/index.ts | ✅ |
superset-frontend/src/explore/types.ts | ✅ |
superset-frontend/src/constants.ts | ✅ |
superset/views/auth.py | ✅ |
superset-frontend/src/views/RootContextProviders.tsx | ✅ |
superset-frontend/src/types/bootstrapTypes.ts | ✅ |
superset-frontend/src/embedded/EmbeddedContextProviders.tsx | ✅ |
superset-frontend/src/dashboard/actions/hydrate.js | ✅ |
superset/views/utils.py | ✅ |
superset/views/base.py | ✅ |
superset/views/core.py | ✅ |
Explore our documentation to understand the languages and file types we support and the files we ignore.
Check out our docs on how you can make Korbit work best for you and your team.
BREAKING CHANGE: Removes flask.flash() messaging infrastructure The Flask flash message system is a legacy feature from when Superset was a server-rendered application. In the current SPA architecture, these messages are never displayed to users because: - Flash messages only render on page load via FlashProvider's componentDidMount - Modern UI interactions use async API calls that don't trigger page reloads - The main consumer (/explore/ POST endpoint) is already marked @deprecated All user-facing notifications are already handled by the frontend toast system, including chart save operations (see saveModalActions.ts) which dispatches success toasts for: - Chart saved/overwritten - Chart added to dashboard - New dashboard created with chart Changes: - Backend: Removed all flash() calls from views (14 occurrences in 4 files) - Backend: Converted error flashes to JSON responses or logging - Backend: Removed redirect_with_flash utility function - Backend: Fixed open redirect vulnerability in dashboard access denial - Frontend: Deleted FlashProvider component and tests - Frontend: Removed flash_messages from CommonBootstrapData type - Frontend: Cleaned up context providers and test fixtures - Frontend: Removed unused getBootstrapData imports Security fixes: - Fixed open redirect vulnerability by using url_for() instead of request.url - Dashboard access denial now uses safe URL construction Code cleanup: - Removed unnecessary pass statements and comments - Converted permalink errors to JSON responses for consistency - Verified no tests depend on flash functionality The application now relies entirely on client-side toast notifications for user feedback, which properly support async operations and provide a consistent UX. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
02df3ec
to
3499c7f
Compare
superset_can_csv: findPermission('can_csv', 'Superset', roles), | ||
common: { | ||
// legacy, please use state.common instead | ||
flash_messages: common?.flash_messages, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Question from review session: Where are server-side messages being processed/summoned now that they're not provided as part of the bootstrap data?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Answer is case by case, but short answer is "as they should" from async calls. Checked that most had been re-implemented the right way since they were used. Also confirmed that old mechanics are to surface "on the next page load", which has very few pre-determined triggers, stuff like logging in maybe.
if not reg: | ||
logger.error(LOGMSG_ERR_SEC_NO_REGISTER_HASH, activation_hash) | ||
flash(as_unicode(self.false_error_message), "danger") | ||
logger.error("Registration activation failed: %s", self.false_error_message) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mistercrunch this is one of the errors that used to be (rightly) surfaced to users, but now might silent in the UI. These (and other?) server-side messages might no longer appear on the frontend.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Relayed: We just need to make sure we have a frontend counterpart for all server side messages that were deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let me confirm that logging in is a SPA operation as it should be as opposed to a backend-round-trip.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Login screen is the only place where this seems to actually work (round-trip + timely flash). Let me refactor this nonsense!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mitigated with a toast, but had to keep the round trip (same as now) at least for now
After removing Flask's flash message system, login errors weren't being displayed. This adds a temporary solution using sessionStorage and toast notifications to show 'Invalid username or password' when login fails. Implementation: - Set a flag in sessionStorage before form submission - On page reload, check if flag exists (indicates failed login) - Show error toast and clear password field for security - Added TODO comment noting this should be replaced with proper SPA auth This addresses reviewer concerns about missing login error messages while keeping the solution simple since it will eventually be replaced with a JSON API approach.
self.pre_delete(item) | ||
except Exception as ex: # pylint: disable=broad-except | ||
flash(str(ex), "danger") | ||
logger.error("Pre-delete error: %s", str(ex)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this probably never should have gone through to user
_("Error: permalink state not found"), status=404 | ||
) | ||
except (ChartNotFoundError, ExplorePermalinkGetFailedError) as ex: | ||
flash(__("Error: %(msg)s", msg=ex.message), "danger") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
function flagged as @deprecated
initial_form_data["slice_id"] = slice_id | ||
if form_data_key: | ||
flash( | ||
_("Form data not found in cache, reverting to chart metadata.") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
part of a function flagged as @deprecated
if form_data_key: | ||
flash( | ||
_( | ||
"Form data not found in cache, reverting to dataset metadata." # noqa: E501 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
part of a function flagged as @deprecated
) | ||
|
||
flash( | ||
_("Chart [{}] was added to dashboard [{}]").format( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
tested that chart adding to dashboard is handled frontend now and flashed properly without these obsolete flash messages
) | ||
flash( | ||
_( | ||
"Dashboard [{}] just got created and chart [{}] was added to it" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
tested that chart adding to dashboard is handled frontend now and flashed properly without these obsolete flash messages
return func(database, user, schema, sql) | ||
|
||
|
||
def redirect_with_flash(url: str, message: str, category: str) -> Response: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not used anymore
superset/views/core.py
Outdated
) | ||
except SupersetSecurityException: | ||
# Return 404 to avoid revealing dashboard existence | ||
abort(404) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
404 is most accurate when you don't have access
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep... it's even in the official spec for 403 (I got curious):
An origin server that wishes to "hide" the current existence of a forbidden target resource MAY instead respond with a status code of 404 (Not Found).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM!
…rmation leakage - Dashboard access denial now returns 404 instead of redirecting - Prevents attackers from enumerating which dashboards exist - Updated tests to expect 404 instead of 302 for access denial - 18 of 20 RBAC tests now pass (2 have teardown issues) Co-Authored-By: Claude <[email protected]>
Using abort(404) inside an exception handler causes issues: - Raises werkzeug.exceptions.NotFound which may not be caught properly - Can leave database transactions in inconsistent state - Causes test teardown failures Solution: Return make_response('Not Found', 404) which returns a proper Flask Response object with 404 status code. All 20 RBAC security tests now pass. Co-Authored-By: Claude <[email protected]>
Cleaner solution for returning 404 in the dashboard access denial case: - Response(status=404) returns an empty response with proper status - Simpler than make_response('Not Found', 404) - Lets browser/client handle 404 appropriately - All tests still pass Co-Authored-By: Claude <[email protected]>
Summary
The Flask flash message system is a legacy feature from when Superset was a server-rendered application. In the current SPA architecture, these messages are never displayed to users because:
All user-facing notifications are already handled by the frontend toast system, including chart save operations (see saveModalActions.ts) which dispatches success toasts for:
Changes
Backend
Frontend
Security Fixes
Code Cleanup
BREAKING CHANGE
Removes flask.flash() messaging infrastructure. However, no actual functionality is lost as the frontend already handles all notifications through its own toast system.
TESTING INSTRUCTIONS
npm test
pytest
ADDITIONAL INFORMATION
The application now relies entirely on client-side toast notifications for user feedback, which properly support async operations and provide a consistent UX.