This is an automated email from the ASF dual-hosted git repository. eschutho pushed a commit to branch fix-query-context-raise-for-access-template-error in repository https://gitbox.apache.org/repos/asf/superset.git
commit 16f7ff747b9c6b8e1726cc1e3618ac6bbc5f749e Author: Elizabeth Thompson <[email protected]> AuthorDate: Tue Sep 8 16:43:31 2026 +0000 fix(query_context): raise 422 not 500 on malformed Jinja in Query datasource access check QueryContextProcessor.raise_for_access() calls security_manager.raise_for_access(query=...) when the datasource is a SQL Lab Query. That method Jinja-renders the query's SQL to resolve the tables it touches; a malformed template raises a raw jinja2.TemplateError that was not caught, producing an opaque 500. Wrap the call in a try/except that converts TemplateError to SupersetTemplateException (status 422), matching the identical pattern already used in explore/utils.py::check_query_access(). Co-Authored-By: Claude Opus 4.6 <[email protected]> --- superset/common/query_context_processor.py | 7 ++++- .../common/test_query_context_processor.py | 30 ++++++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/superset/common/query_context_processor.py b/superset/common/query_context_processor.py index 2c27fb9fb06..1f845cf9a45 100644 --- a/superset/common/query_context_processor.py +++ b/superset/common/query_context_processor.py @@ -26,6 +26,7 @@ import pandas as pd import pyarrow as pa from flask import current_app from flask_babel import gettext as _ +from jinja2.exceptions import TemplateError from pandas.api.types import infer_dtype from superset.common.chart_data import ChartDataResultFormat @@ -45,6 +46,7 @@ from superset.daos.chart import ChartDAO from superset.exceptions import ( QueryObjectValidationError, SupersetException, + SupersetTemplateException, ) from superset.explorables.base import Explorable from superset.extensions import cache_manager, security_manager @@ -933,7 +935,10 @@ class QueryContextProcessor: # come first to avoid rendering caller-supplied input for a resource the # caller is not allowed to access. if self._qc_datasource.type == DatasourceType.QUERY: - security_manager.raise_for_access(query=self._qc_datasource) + try: + security_manager.raise_for_access(query=self._qc_datasource) + except TemplateError as ex: + raise SupersetTemplateException(str(ex)) from ex else: security_manager.raise_for_access(query_context=self._query_context) diff --git a/tests/unit_tests/common/test_query_context_processor.py b/tests/unit_tests/common/test_query_context_processor.py index 5dc21d12b85..777c188787d 100644 --- a/tests/unit_tests/common/test_query_context_processor.py +++ b/tests/unit_tests/common/test_query_context_processor.py @@ -2220,6 +2220,36 @@ def test_raise_for_access_evaluates_access_before_validate(): query.validate.assert_not_called() +def test_raise_for_access_wraps_template_error_for_query_datasource(): + """ + When the datasource is a SQL Lab Query and raise_for_access() Jinja-renders + malformed SQL, the raw jinja2 TemplateError must be wrapped in + SupersetTemplateException (422) instead of leaking as an unhandled 500. + """ + from jinja2.exceptions import TemplateError, TemplateSyntaxError + + from superset.exceptions import SupersetTemplateException + from superset.utils.core import DatasourceType + + query = MagicMock() + query_context = MagicMock() + query_context.queries = [query] + query_context.datasource.type = DatasourceType.QUERY + + processor = QueryContextProcessor(query_context) + + with patch( + "superset.common.query_context_processor.security_manager.raise_for_access", + side_effect=TemplateSyntaxError("unexpected end of template", lineno=1), + ): + with pytest.raises(SupersetTemplateException) as exc: + processor.raise_for_access() + + assert exc.value.status == 422 + assert isinstance(exc.value.__cause__, TemplateError) + query.validate.assert_not_called() + + def test_grouping_sets_fallback_handles_adhoc_and_physical_columns() -> None: """ The fallback used on engines without native GROUPING SETS support must
