Skip to content

fix(query_context): raise 422 not 500 on malformed Jinja in Query datasource access check - #44011

Merged
eschutho merged 1 commit into
apache:masterfrom
eschutho:fix-query-context-raise-for-access-template-error
Sep 24, 2026
Merged

eschutho merged 1 commit into
apache:masterfrom
eschutho:fix-query-context-raise-for-access-template-error

Conversation

@eschutho

@eschutho eschutho commented Sep 8, 2026

Copy link
Copy Markdown
Member

SUMMARY

QueryContextProcessor.raise_for_access() calls security_manager.raise_for_access(query=...) when the datasource is a SQL Lab Query (i.e. DatasourceType.QUERY — the "explore/chart a SQL Lab result without saving a dataset" flow). That method internally Jinja-renders the query's SQL to resolve the tables it touches. If the SQL contains a malformed Jinja template, a raw jinja2.TemplateError propagates uncaught all the way to the Flask API layer, producing an opaque 500.

This wraps the call in try/except TemplateError → SupersetTemplateException (status 422), exactly matching the pattern already used in superset/explore/utils.py::check_query_access() for the same security_manager.raise_for_access(query=...) call. The global SupersetException error handler in superset/views/error_handling.py converts it to a proper JSON error response automatically.

Sibling fix in the same bug family: #43866 (fix(sql_lab): raise 400 not 500 on malformed Jinja during CSV export access check).

BEFORE/AFTER SCREENSHOTS OR ANIMATED GIF

N/A — backend-only error handling change.

TESTING INSTRUCTIONS

  1. New unit test test_raise_for_access_wraps_template_error_for_query_datasource in tests/unit_tests/common/test_query_context_processor.py — mirrors the existing test_raise_for_access_evaluates_access_before_validate test structure.
  2. Verified empirically: test fails on pre-fix code (raw TemplateSyntaxError leaks), passes after the fix.
  3. Existing sibling test test_raise_for_access_evaluates_access_before_validate continues to pass (no regression to the DatasourceType.TABLE path).
pytest tests/unit_tests/common/test_query_context_processor.py -k "test_raise_for_access" -v

ADDITIONAL INFORMATION

  • Has associated issue:
  • Required feature flags:
  • Changes UI
  • Includes DB Migration (follow approval process in SIP-59)
    • Migration is atomic, supports rollback & is backwards-compatible
    • Confirm DB migration upgrade and downgrade tested
    • Runtime estimates and downtime expectations provided
  • Introduces new feature or API
  • Removes existing feature or API

@bito-code-review

bito-code-review Bot commented Sep 8, 2026 •

Copy link
Copy Markdown
Contributor

Code Review Agent Run #114d7e

Actionable Suggestions - 0
Review Details
  • Files reviewed - 4 · Commit Range: e15e95a..ad7ac16
    • superset/commands/report/alert.py
    • superset/common/query_context_processor.py
    • tests/unit_tests/commands/report/alert_test.py
    • tests/unit_tests/common/test_query_context_processor.py
  • Files skipped - 0
  • Tools
    • MyPy (Static Code Analysis) - ✔︎ Successful
    • Astral Ruff (Static Code Analysis) - ✔︎ Successful
    • Whispers (Secret Scanner) - ✔︎ Successful
    • Detect-secrets (Secret Scanner) - ✔︎ Successful

Bito Usage Guide

Commands

Type the following command in the pull request comment and save the comment.

  • /review - Manually triggers an incremental AI Review.

  • /review full - Manually triggers a full AI Review.

  • /pause - Pauses automatic reviews on this pull request.

  • /resume - Resumes automatic reviews.

  • /resolve - Marks all Bito-posted review comments as resolved.

  • /abort - Cancels all in-progress reviews.

Refer to the documentation for additional commands.

Configuration

This repository uses Superset You can customize the agent settings here or contact your Bito workspace admin at evan@preset.io.

Documentation & Help

AI Code Review powered by Bito Logo

@netlify

netlify Bot commented Sep 8, 2026 •

Copy link
Copy Markdown

✅ Deploy Preview for superset-docs-preview ready!

Name Link
🔨 Latest commit 552f526
🔍 Latest deploy log https://app.netlify.com/projects/superset-docs-preview/deploys/6ab43039d7ac9e0008dea101
😎 Deploy Preview https://deploy-preview-44011--superset-docs-preview.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@eschutho eschutho closed this Sep 8, 2026
@eschutho
eschutho deleted the fix-query-context-raise-for-access-template-error branch September 8, 2026 17:01
@eschutho
eschutho restored the fix-query-context-raise-for-access-template-error branch September 8, 2026 17:03
@eschutho eschutho reopened this Sep 8, 2026
@eschutho

eschutho commented Sep 8, 2026

Copy link
Copy Markdown
Member Author

Note: This PR currently includes an extraneous commit (fix(alerts): wrap Jinja rendering errors in AlertCommand._execute_query) in its history because the eschutho fork's master is far behind apache/superset:master and the PAT lacks workflow scope, preventing a clean push based on current upstream master. The actual fix is the single top commit — fix(query_context): raise 422 not 500 on malformed Jinja in Query datasource access check. A rebase onto current master will be needed before merge; happy to do that once the fork is synced or a token with workflow scope is available.

@rebenitez1802 rebenitez1802 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Request changes: the new query_context fix is correct, secure, and well-tested — but the PR also carries a stale duplicate of already-merged #42714, which is the only reason it conflicts and hides a regression trap. Drop that commit and this is a clean approve.

🔴 High — First commit duplicates already-merged #42714 and its conflict drops _validate_rendered_sql
Commit e15e95af ("fix(alerts): wrap Jinja rendering errors…") is already on master — it landed as #42714 (7c03736623), same title, and master already has process_template inside the try plus the identical test_execute_query_wraps_template_rendering_error. Since #42714 merged, master also added self._validate_rendered_sql(rendered_sql) (via #42929) right after that line. git merge-tree origin/master <head> shows the only conflict is here in alert.py:

            rendered_sql = sql_template.process_template(...)
<<<<<<< origin/master
            self._validate_rendered_sql(rendered_sql)
=======
>>>>>>> <pr head>
            limited_rendered_sql = ...apply_limit_to_sql(...)

Resolving it by taking "the PR side" silently deletes master's _validate_rendered_sql call (single-statement + read-only-DML enforcement) — a real regression. Fix: rebase onto master and drop commit e15e95af entirely (the alert.py hunk and the alert test are both redundant with master); keep only the query_context_processor.py change + its test, which merge cleanly.

🟢 Low — query_context test asserts the exception type but not the 422 status the PR is about
test_raise_for_access_wraps_template_error_for_query_datasource only does pytest.raises(SupersetTemplateException). The type implies 422 today (exceptions.py:201), but the PR's stated purpose is the status code, and nothing pins it — a future refactor making the exception a 500 would pass silently. Fix: with pytest.raises(SupersetTemplateException) as exc: … assert exc.value.status == 422.

🟢 Low — Neither template-wrap test asserts cause chaining
Both fixes correctly preserve the cause via raise … from ex, but the tests don't check it. Fix: add assert isinstance(exc.value.__cause__, TemplateError) so a later refactor can't drop the chaining unnoticed.

🟢 Low — Scoping the wrap to only the DatasourceType.QUERY branch is intentional — no action
For a reviewer's benefit: leaving the else (query_context=…) branch unwrapped matches the sibling check_query_access in superset/explore/utils.py, and omitting allow_query_authorship_bypass=True here is also correct (this path re-checks access on every chart/dashboard view). Both are deliberate; flagging only so they don't get "fixed."

Also checked (no action needed): the except TemplateError in query_context_processor.raise_for_access is narrowly scoped — SupersetSecurityException (403) is not a TemplateError subclass, so access denials still propagate as 403; and the wrapped str(ex) at 422 exposes no more than the pre-fix behavior already did (same message, previously surfaced as a 500).

@github-actions github-actions Bot added the requires:rebase Requires rebasing on top of current master label Sep 9, 2026
@eschutho
eschutho force-pushed the fix-query-context-raise-for-access-template-error branch from ad7ac16 to 95102ac Compare September 22, 2026 23:31
@bito-code-review

bito-code-review Bot commented Sep 23, 2026 •

Copy link
Copy Markdown
Contributor

Code Review Agent Run #4968a6

Actionable Suggestions - 0
Review Details
  • Files reviewed - 2 · Commit Range: 95102ac..95102ac
    • superset/common/query_context_processor.py
    • tests/unit_tests/common/test_query_context_processor.py
  • Files skipped - 0
  • Tools
    • MyPy (Static Code Analysis) - ✔︎ Successful
    • Astral Ruff (Static Code Analysis) - ✔︎ Successful
    • Whispers (Secret Scanner) - ✔︎ Successful
    • Detect-secrets (Secret Scanner) - ✔︎ Successful

Bito Usage Guide

Commands

Type the following command in the pull request comment and save the comment.

  • /review - Manually triggers an incremental AI Review.

  • /review full - Manually triggers a full AI Review.

  • /pause - Pauses automatic reviews on this pull request.

  • /resume - Resumes automatic reviews.

  • /resolve - Marks all Bito-posted review comments as resolved.

  • /abort - Cancels all in-progress reviews.

Refer to the documentation for additional commands.

Configuration

This repository uses Superset You can customize the agent settings here or contact your Bito workspace admin at evan@preset.io.

Documentation & Help

AI Code Review powered by Bito Logo

@rebenitez1802 rebenitez1802 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approve: the blocking issue is resolved — thanks for dropping the stale alert commit. The PR is now a focused single-commit change to query_context_processor.py + its test, and the raise_for_access wrap is correct, security-scoped, and well-tested. One mechanical step before merge, plus two optional nits.

🟡 Medium — Still CONFLICTING, but it's now a trivial import-adjacency conflict (rebase to clear)
The branch is still on its old base, so git merge-tree origin/master <head> shows the raise_for_access body and the SupersetTemplateException import both auto-merge cleanly — the only conflict is one import line at the top of the file:

<<<<<<< origin/master
from pandas.api.types import infer_dtype      # added on master
=======
from jinja2.exceptions import TemplateError   # added by this PR
>>>>>>> <pr head>

Both sides just inserted a different import after from flask_babel import gettext as _. Resolution: keep both lines (isort order puts from jinja2.exceptions import TemplateError before from pandas.api.types import infer_dtype). A rebase / "Update branch" clears it — no code risk.

🟢 Low — Test asserts the exception type but not the 422 status the PR is about
test_raise_for_access_wraps_template_error_for_query_datasource only does pytest.raises(SupersetTemplateException). The type implies 422 today (exceptions.py), but nothing pins the status the PR exists to guarantee. Optional: with pytest.raises(SupersetTemplateException) as exc: … assert exc.value.status == 422.

🟢 Low — Test doesn't assert cause chaining
The fix correctly preserves the cause via raise … from ex, but the test doesn't check it. Optional: assert isinstance(exc.value.__cause__, TemplateError) so a later refactor can't silently drop the chaining.

Approving so this isn't gated on the two optional nits; just needs the rebase to become mergeable.

…asource 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 <noreply@anthropic.com>
@rusackas
rusackas force-pushed the fix-query-context-raise-for-access-template-error branch from 95102ac to 552f526 Compare September 23, 2026 20:01
@rusackas rusackas removed the requires:rebase Requires rebasing on top of current master label Sep 23, 2026
Comment on lines +2245 to +2246
with pytest.raises(SupersetTemplateException):
processor.raise_for_access()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: The test checks only the exception class, so it passes even if SupersetTemplateException.status is not 422 and cannot protect the API contract this change targets.

Assessment: 🟠 Major · 🔁 Occurrence: Rarely · 🏷️ Api mismatch

Use CodeAnt Skill Fix in Cursor Fix in VSCode Claude

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** tests/unit_tests/common/test_query_context_processor.py
**Line:** 2245:2246
**Comment:**
	*Api Mismatch: The test checks only the exception class, so it passes even if `SupersetTemplateException.status` is not 422 and cannot protect the API contract this change targets.

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 fix
👍 | 👎

@bito-code-review

Copy link
Copy Markdown
Contributor

The flagged issue is correct. The current test only verifies that a SupersetTemplateException is raised, but it does not assert that the exception status is 422, which is necessary to ensure the API contract is properly enforced.

To resolve this, you should update the test to explicitly check the status code of the raised exception. You can modify the test as follows:

    with pytest.raises(SupersetTemplateException) as excinfo:
        processor.raise_for_access()
    assert excinfo.value.status == 422

I have checked the PR comments, and there are no other comments to address. Would you like me to fetch all comments to validate and implement fixes for any other issues?

tests/unit_tests/common/test_query_context_processor.py

with pytest.raises(SupersetTemplateException) as excinfo:
        processor.raise_for_access()
    assert excinfo.value.status == 422

@codecov

codecov Bot commented Sep 23, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 81.06%. Comparing base (d7a918b) to head (552f526).
⚠️ Report is 2 commits behind head on master.

Additional details and impacted files
@@           Coverage Diff           @@
##           master   #44011   +/-   ##
=======================================
  Coverage   81.06%   81.06%           
=======================================
  Files        2955     2955           
  Lines      178300   178304    +4     
  Branches    41307    41307           
=======================================
+ Hits       144533   144539    +6     
+ Misses      31056    31055    -1     
+ Partials     2711     2710    -1     
Flag Coverage Δ
hive 36.80% <20.00%> (-0.01%) ⬇️
mysql 55.97% <20.00%> (-0.01%) ⬇️
postgres 55.97% <20.00%> (-0.01%) ⬇️
presto 38.72% <20.00%> (-0.01%) ⬇️
python 85.36% <100.00%> (+<0.01%) ⬆️
sqlite 55.69% <20.00%> (-0.01%) ⬇️
unit 77.63% <100.00%> (+<0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@bito-code-review

bito-code-review Bot commented Sep 23, 2026 •

Copy link
Copy Markdown
Contributor

Code Review Agent Run #d4860b

Actionable Suggestions - 0
Review Details
  • Files reviewed - 2 · Commit Range: 552f526..552f526
    • superset/common/query_context_processor.py
    • tests/unit_tests/common/test_query_context_processor.py
  • Files skipped - 0
  • Tools
    • MyPy (Static Code Analysis) - ✔︎ Successful
    • Astral Ruff (Static Code Analysis) - ✔︎ Successful
    • Whispers (Secret Scanner) - ✔︎ Successful
    • Detect-secrets (Secret Scanner) - ✔︎ Successful

Bito Usage Guide

Commands

Type the following command in the pull request comment and save the comment.

  • /review - Manually triggers an incremental AI Review.

  • /review full - Manually triggers a full AI Review.

  • /pause - Pauses automatic reviews on this pull request.

  • /resume - Resumes automatic reviews.

  • /resolve - Marks all Bito-posted review comments as resolved.

  • /abort - Cancels all in-progress reviews.

Refer to the documentation for additional commands.

Configuration

This repository uses Superset You can customize the agent settings here or contact your Bito workspace admin at evan@preset.io.

Documentation & Help

AI Code Review powered by Bito Logo

@eschutho
eschutho merged commit 855ca22 into apache:master Sep 24, 2026
80 checks passed
villebro pushed a commit that referenced this pull request Sep 30, 2026
…asource access check (#44011)

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
(cherry picked from commit 855ca22)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants