This is an automated email from the ASF dual-hosted git repository.
eschutho pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/superset.git
The following commit(s) were added to refs/heads/master by this push:
new 5986fe92c2f fix(rls): roll back db.session after RLS failure in
get_from_clause (#43883)
5986fe92c2f is described below
commit 5986fe92c2f97711916d777e636ec8acd4ed138d
Author: Elizabeth Thompson <[email protected]>
AuthorDate: Tue Sep 8 15:04:32 2026 -0700
fix(rls): roll back db.session after RLS failure in get_from_clause (#43883)
Co-authored-by: Claude Opus 4.6 <[email protected]>
---
superset/models/helpers.py | 4 ++++
.../models/test_virtual_dataset_format.py | 25 ++++++++++++++++++++++
2 files changed, 29 insertions(+)
diff --git a/superset/models/helpers.py b/superset/models/helpers.py
index 9589613f674..8d2cae5ce36 100644
--- a/superset/models/helpers.py
+++ b/superset/models/helpers.py
@@ -3640,6 +3640,10 @@ class ExploreMixin: # pylint:
disable=too-many-public-methods
from_sql = parsed_script.format()
except Exception as ex: # pylint: disable=broad-except
+ # A caught DB error can leave db.session in "pending rollback"
+ # state, which would poison unrelated queries later in this
request.
+ db.session.rollback() # pylint:
disable=consider-using-transaction
+
# RLS injection failures fail closed: only continue when it is
# positively confirmed that no RLS predicates apply to the
# referenced tables; any other outcome aborts the query.
diff --git a/tests/unit_tests/models/test_virtual_dataset_format.py
b/tests/unit_tests/models/test_virtual_dataset_format.py
index c063d32efb7..ee0898c09dd 100644
--- a/tests/unit_tests/models/test_virtual_dataset_format.py
+++ b/tests/unit_tests/models/test_virtual_dataset_format.py
@@ -36,6 +36,7 @@ from unittest.mock import MagicMock, patch
import pytest
from flask import Flask
+from sqlalchemy.exc import OperationalError
from sqlalchemy.sql.elements import TextClause
from superset.exceptions import QueryObjectValidationError
@@ -472,3 +473,27 @@ class TestVirtualDatasetRLSFailClosed:
with pytest.raises(QueryObjectValidationError):
virtual_datasource.get_from_clause(template_processor=None)
+
+ @patch("superset.models.helpers.db")
+ @patch(
+ "superset.models.helpers.get_predicates_for_table",
+ return_value=["user_id = 42"],
+ )
+ @patch(
+ "superset.models.helpers.apply_rls",
+ side_effect=OperationalError("SSL connection closed unexpectedly", {},
None),
+ )
+ def test_get_from_clause_rolls_back_session_on_rls_failure(
+ self,
+ mock_apply_rls: MagicMock,
+ mock_get_predicates: MagicMock,
+ mock_db: MagicMock,
+ virtual_datasource: MagicMock,
+ app: Flask,
+ ) -> None:
+ _set_virtual_sql(virtual_datasource, "SELECT pen_id FROM public.pens")
+
+ with pytest.raises(QueryObjectValidationError):
+ virtual_datasource.get_from_clause(template_processor=None)
+
+ mock_db.session.rollback.assert_called_once()