You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by el...@apache.org on 2026/08/08 16:33:24 UTC

(superset) branch fix-format-sql-jinja-undefined-error created (now 9d633f3d94d)

This is an automated email from the ASF dual-hosted git repository.

eschutho pushed a change to branch fix-format-sql-jinja-undefined-error
in repository https://gitbox.apache.org/repos/asf/superset.git


      at 9d633f3d94d fix(sqllab): wrap process_template() in format_sql to prevent raw UndefinedError leak (SC-116908)

This branch includes the following new commits:

     new 9d633f3d94d fix(sqllab): wrap process_template() in format_sql to prevent raw UndefinedError leak (SC-116908)

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



(superset) 01/01: fix(sqllab): wrap process_template() in format_sql to prevent raw UndefinedError leak (SC-116908)

Posted by el...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

eschutho pushed a commit to branch fix-format-sql-jinja-undefined-error
in repository https://gitbox.apache.org/repos/asf/superset.git

commit 9d633f3d94d57544b0ef55e98c0bcdcd3dc942af
Author: Elizabeth Thompson <es...@gmail.com>
AuthorDate: Sat Aug 8 16:32:22 2026 +0000

    fix(sqllab): wrap process_template() in format_sql to prevent raw UndefinedError leak (SC-116908)
    
    format_sql() (POST /api/v1/sqllab/format_sql/) calls process_template()
    with no catch for jinja2 exceptions. When an undefined Jinja variable is
    accessed via attribute/subscript (e.g. {{ tbl.name }}), process_template()
    re-raises the raw jinja2.exceptions.UndefinedError instead of converting
    it, so it escapes to the global exception handler as an opaque 500
    instead of a typed 4xx.
    
    Mirrors QueryEstimationCommand.run() (#42757): catch TemplateError,
    raise SupersetErrorException(status=400). Same bug class as #42366,
    #42401, #42714, #42757, #42802, #42851 — 7th call site of
    process_template()'s bare-raise fallback in this series.
    
    Fixes SUPERSET-PYTHON (raw UndefinedError leak, format_sql call site)
---
 superset/sqllab/api.py                       | 12 ++++++++++++
 tests/integration_tests/sql_lab/api_tests.py | 23 +++++++++++++++++++++++
 2 files changed, 35 insertions(+)

diff --git a/superset/sqllab/api.py b/superset/sqllab/api.py
index 5b6d585f9c7..62e5a683cb3 100644
--- a/superset/sqllab/api.py
+++ b/superset/sqllab/api.py
@@ -23,6 +23,7 @@ from flask import current_app as app, request, Response
 from flask_appbuilder import permission_name
 from flask_appbuilder.api import expose, protect, rison as parse_rison, safe
 from flask_appbuilder.models.sqla.interface import SQLAInterface
+from jinja2.exceptions import TemplateError
 from marshmallow import ValidationError
 from werkzeug.utils import secure_filename
 
@@ -37,6 +38,8 @@ from superset.commands.sql_lab.streaming_export_command import (
 from superset.constants import MODEL_API_RW_METHOD_PERMISSION_MAP
 from superset.daos.database import DatabaseDAO
 from superset.daos.query import QueryDAO
+from superset.errors import ErrorLevel, SupersetError, SupersetErrorType
+from superset.exceptions import SupersetErrorException
 from superset.extensions import event_logger, security_manager
 from superset.jinja_context import get_template_processor
 from superset.models.sql_lab import Query
@@ -266,6 +269,15 @@ class SqlLabRestApi(BaseSupersetApi):
                                 "Invalid template parameter %s. Skipping processing",
                                 str(template_params),
                             )
+                        except TemplateError as ex:
+                            raise SupersetErrorException(
+                                SupersetError(
+                                    message=str(ex),
+                                    error_type=SupersetErrorType.GENERIC_COMMAND_ERROR,
+                                    level=ErrorLevel.ERROR,
+                                ),
+                                status=400,
+                            ) from ex
 
             result = SQLScript(sql, model.get("engine", database_engine)).format()
             return self.response(200, result=result)
diff --git a/tests/integration_tests/sql_lab/api_tests.py b/tests/integration_tests/sql_lab/api_tests.py
index 4329946fe89..4527112000c 100644
--- a/tests/integration_tests/sql_lab/api_tests.py
+++ b/tests/integration_tests/sql_lab/api_tests.py
@@ -336,6 +336,29 @@ class TestSqlLabApi(SupersetTestCase):
         assert "{{tbl}}" not in resp_data["result"]
         assert resp_data["result"] == expected
 
+    def test_format_sql_request_with_undefined_jinja_attribute(self):
+        self.login(ADMIN_USERNAME)
+        example_db = get_example_database()
+
+        # Attribute access on an undefined Jinja variable (``tbl`` is not in the
+        # template params) raises a jinja2 ``UndefinedError`` from within
+        # ``process_template``. This should surface as a typed 400, not an opaque
+        # 500 from the global exception handler. A non-empty ``template_params``
+        # dict is required so the endpoint actually invokes ``process_template``.
+        data = {
+            "sql": "select * from {{ tbl.name }}",
+            "database_id": example_db.id,
+            "template_params": json.dumps({"unrelated": "value"}),
+        }
+        rv = self.client.post(
+            "/api/v1/sqllab/format_sql/",
+            json=data,
+        )
+        resp_data = json.loads(rv.data.decode("utf-8"))
+        assert rv.status_code == 400
+        assert "tbl" in resp_data["errors"][0]["message"]
+        assert "undefined" in resp_data["errors"][0]["message"]
+
     @mock.patch("superset.commands.sql_lab.results.results_backend_use_msgpack", False)
     def test_execute_required_params(self):
         self.login(ADMIN_USERNAME)