Skip to content

fix(sql lab): scope write and DDL targets in per-table access checks - #45936

Open
sha174n wants to merge 3 commits into
apache:masterfrom
sha174n:fix-sqllab-write-target-scoping
Open

sha174n wants to merge 3 commits into
apache:masterfrom
sha174n:fix-sqllab-write-target-scoping

Conversation

@sha174n

@sha174n sha174n commented Nov 1, 2026

Copy link
Copy Markdown
Contributor

SUMMARY

Adds a write and DDL target access check, SupersetSecurityManager.raise_for_write_target_access, that the query execution paths call alongside the existing per-table check: SQL Lab execution, MCP execute_sql, the alert query run, and alert create/update query validation.

The existing per-table check builds its table set from a statement's read sources (the FROM / JOIN references). The target a statement writes to, alters or drops is modelled elsewhere in the AST and is not part of that set. The new check covers that target when it is a registered physical dataset outside all of the user's grants (no datasource_access on it, no schema_access on its schema, no catalog_access on its catalog) and not owned by them.

Behaviour is unchanged for:

  • unregistered tables, temporary and session objects, and tables created earlier in the same script
  • new-object creation (CREATE TABLE, CTAS, rename to a new name) and structure-copy sources
  • tables covered by schema or catalog access, dataset owners, and users with database access
  • deployments that override raise_for_access or configure EXTRA_RAISE_FOR_ACCESS_BYPASS

raise_for_access (signature and body) and result/export re-validation are unchanged.

TESTING INSTRUCTIONS

  • tests/unit_tests/sql/parse_tests.py: write/DDL target extraction across dialects (multi-table UPDATE/DELETE, T-SQL target aliases, MERGE, INSERT ALL, COPY INTO, SWAP WITH, CREATE INDEX ... ON, CTE-nested DML, temporary objects, script-created tables).
  • tests/unit_tests/security/manager_test.py: allow/deny matrix for the new check, including a corpus of statements that must keep working unchanged, custom security manager subclasses, the access hook, and result re-validation of an executed script.

ADDITIONAL INFORMATION

  • Has associated issue:
  • Required feature flags:
  • Changes UI
  • Includes DB Migration
  • Introduces new feature or API
  • Removes existing feature or API

🤖 Generated with Claude Code

@netlify

netlify Bot commented Nov 1, 2026

Copy link
Copy Markdown

✅ Deploy Preview for superset-docs-preview ready!

Name Link
🔨 Latest commit 49d3c4a
🔍 Latest deploy log https://app.netlify.com/projects/superset-docs-preview/deploys/6ae7cc20b95cf5ae84c58887
😎 Deploy Preview https://deploy-preview-45936--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.

@codeant-ai-for-open-source

codeant-ai-for-open-source Bot commented Nov 1, 2026 •

Copy link
Copy Markdown
Contributor

CodeAnt  CodeAnt PR Risk

🟡  Medium Risk

  • The PR needs attention before merging because MCP write authorization may not match the SQL that is ultimately executed.
  • Templated SQL is rendered for target checks and passed to execution separately, so a varying template could write to an unapproved registered table.

Assessed commit: b3bee62529b2

@codecov

codecov Bot commented Nov 1, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 19.41176% with 274 lines in your changes missing coverage. Please review.
✅ Project coverage is 65.27%. Comparing base (a6f30aa) to head (ea4f2d6).
⚠️ Report is 1 commits behind head on master.

Files with missing lines Patch % Lines
superset/sql/parse.py 19.29% 184 Missing ⚠️
superset/security/manager.py 19.10% 69 Missing and 3 partials ⚠️
superset/mcp_service/sql_lab/tool/execute_sql.py 10.00% 18 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master   #45936      +/-   ##
==========================================
- Coverage   65.35%   65.27%   -0.08%     
==========================================
  Files        3083     3083              
  Lines      211333   211666     +333     
  Branches    49823    49904      +81     
==========================================
+ Hits       138110   138175      +65     
- Misses      70041    70306     +265     
- Partials     3182     3185       +3     
Flag Coverage Δ
hive 34.00% <17.94%> (-0.05%) ⬇️
mysql 51.72% <19.41%> (-0.10%) ⬇️
postgres 51.74% <19.41%> (-0.10%) ⬇️
presto 35.64% <17.94%> (-0.06%) ⬇️
python 52.04% <19.41%> (-0.10%) ⬇️
sqlite 51.43% <19.41%> (-0.10%) ⬇️

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.

@sadpandajoe
sadpandajoe requested a review from rusackas November 2, 2026 18:21
@github-actions github-actions Bot added the requires:rebase Requires rebasing on top of current master label Nov 4, 2026
@sha174n
sha174n force-pushed the fix-sqllab-write-target-scoping branch from 49d3c4a to b3bee62 Compare November 10, 2026 15:48
@github-actions github-actions Bot removed the requires:rebase Requires rebasing on top of current master label Nov 10, 2026
sha174n and others added 3 commits November 11, 2026 11:34
Add a write and DDL target access check,
SupersetSecurityManager.raise_for_write_target_access, that the query
execution paths call alongside the existing per-table check: SQL Lab
execution (templated SQL is checked once, in its rendered form), MCP
execute_sql, the alert query run, and alert create/update query
validation, so validation and execution agree.

It covers the target of a statement when that target is a registered
physical dataset outside all of the user's grants (no datasource_access
on it, no schema_access on its schema, no catalog_access on its catalog,
checked against both the dataset's stored permissions and the ones
computed for the target) and not owned by them. This includes each
table a multi-table DELETE modifies, the tables a MySQL multi-table
UPDATE qualifies its SET columns with (or its only table, when the
other joined sources are derived tables), the table behind a T-SQL
UPDATE or DELETE target alias, each INSERT ALL target, a COPY INTO
table, both tables of ALTER TABLE ... SWAP WITH, the table of CREATE
INDEX ... ON, a table or view being dropped, altered or replaced, and
the targets of INSERT, UPDATE, DELETE or MERGE statements nested in a
WITH clause. Target aliases are compared the way the dialect resolves
identifiers (quoted names exactly, unquoted names normalized), and
statement modifiers read as tables (TOP, QUICK, LOW_PRIORITY, ...) are
only set aside in DELETE and UPDATE target lists. It parses
and qualifies the SQL the same way as the per-table check and
short-circuits on the same database-level access, before any parsing;
SQL without any write or DDL target returns before rendering.

Temporary and session objects, tables created earlier in the same
script, unregistered tables, structure-copy sources and new-object
creation are unchanged, as are T-SQL updatable CTEs of the statement's
own WITH clause, and targets whose catalog is not known on an engine
that models catalogs. Deployments that override the per-table check or
configure an access hook (EXTRA_RAISE_FOR_ACCESS_BYPASS) keep their own
semantics: the new check is skipped for them. The existing per-table check
(raise_for_access, whose signature and body are unchanged) and
result/export re-validation are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Render the template once, authorize that rendered string as well as the
template, and hand it to the executor without template_params so it runs
unchanged. Rendered SQL that still contains Jinja markup is rejected.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@sha174n
sha174n force-pushed the fix-sqllab-write-target-scoping branch from 55b1896 to ea4f2d6 Compare November 11, 2026 11:36

This branch has not been deployed

No deployments
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.

1 participant