Skip to content

fix(sqllab): let schema grants authorize SQL Lab again - #44968

Open
AmoghAtreya wants to merge 13 commits into
apache:masterfrom
AmoghAtreya:fix/sqllab-schema-access-opt-out
Open

AmoghAtreya wants to merge 13 commits into
apache:masterfrom
AmoghAtreya:fix/sqllab-schema-access-opt-out

Conversation

@AmoghAtreya

@AmoghAtreya AmoghAtreya commented Oct 4, 2026 •

Copy link
Copy Markdown
Contributor

SUMMARY

Fixes #44903. After #40409, SQL Lab required datasource_access on a registered dataset for every referenced table. A Gamma user with sql_lab plus schema_access and catalog_access could still browse the schema and open charts, but every SQL Lab query was denied. The error read as if those schema grants were missing, and there was no configuration to restore the previous behavior. Registering every table as a dataset does not scale for schemas where tables are added and renamed often, and database_access is broader than a single schema.

SQLLAB_REQUIRE_DATASET_MATCH defaults to True, so the dataset-match requirement stays on unless an admin opts out. Set it to False to authorize SQL Lab from schema_access or catalog_access alone. That grant then covers every table in the schema, including tables that are not registered as datasets.

The flag covers the SQL Lab paths that execute a query or return its rows:

  • query execution
  • result fetch
  • CSV and streaming export
  • cost estimates
  • SQL formatting
  • the MCP execute_sql tool

Charts and Explore already honor schema_access and catalog_access and are unchanged. Reports, alerts, MetaDB, and SQL validation keep requiring a dataset match.

When the requirement is left on, a denial names the dataset requirement. It says schema_access and catalog_access do not authorize the query, instead of reading as if those grants are absent.

BEFORE/AFTER SCREENSHOTS OR ANIMATED GIF

N/A. Backend permission check and configuration only.

TESTING INSTRUCTIONS

  1. Use a database that supports catalogs, with "Allow changing catalogs" enabled. Create a non-admin user with the sql_lab role and only these data grants:
    • catalog_access on [Database].[catalog]
    • schema_access on [Database].[catalog].[schema]
    • no database_access
    • no per-table datasource_access
  2. Leave SQLLAB_REQUIRE_DATASET_MATCH unset (default True). In SQL Lab, run SELECT * FROM schema.table LIMIT 100. The query is denied. The error says a registered dataset with datasource_access is required, and that schema_access and catalog_access do not authorize the query.
  3. Set SQLLAB_REQUIRE_DATASET_MATCH = False in superset_config.py and restart. Run the same query. It succeeds.
  4. Set the flag back to True. Grant datasource_access on a registered dataset for that table and run the query again. It succeeds.
  5. With the flag at either value, open a chart or dashboard backed by a dataset in that schema. It still loads for a user who holds schema_access.
pytest tests/unit_tests/sqllab/test_requires_dataset_match.py \
  tests/unit_tests/sqllab/api_test.py \
  tests/unit_tests/commands/sql_lab/test_estimate.py \
  tests/unit_tests/security/manager_test.py \
  -k "dataset_match or format_sql or catalog_self_reference"

ADDITIONAL INFORMATION

@github-actions github-actions Bot added api Related to the REST API doc Namespace | Anything related to documentation labels Oct 4, 2026
@netlify

netlify Bot commented Oct 4, 2026 •

Copy link
Copy Markdown

✅ Deploy Preview for superset-docs-preview ready!

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

Comment thread docs/admin_docs/security/security.mdx Outdated
@bito-code-review

Copy link
Copy Markdown
Contributor

The review comment is correct. The documentation in docs/admin_docs/security/security.mdx incorrectly implies that catalog_access is restricted to a single schema, whereas it actually authorizes access across the entire catalog.

To resolve this, the sentence should be updated to clarify that catalog_access provides broader scope. I have implemented the correction below:

- `schema_access` and `catalog_access` let the user browse that schema in SQL Lab and still authorize charts, but they do not authorize query execution.
+ `schema_access` lets the user browse that schema in SQL Lab, and `catalog_access` lets the user browse the catalog, and both still authorize charts, but they do not authorize query execution.

I have checked the other comments on this PR. Would you like me to fetch all comments, validate them, and implement fixes for the rest as well?

docs/admin_docs/security/security.mdx

- `schema_access` and `catalog_access` let the user browse that schema in SQL Lab and still authorize charts, but they do not authorize query execution.
+ `schema_access` lets the user browse that schema in SQL Lab, and `catalog_access` lets the user browse the catalog, and both still authorize charts, but they do not authorize query execution.

Comment thread superset/commands/sql_lab/estimate.py
Comment thread superset/mcp_service/sql_lab/tool/execute_sql.py

@bito-code-review bito-code-review Bot 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.

Code Review Agent Run #1629cf

Actionable Suggestions - 3
  • tests/unit_tests/sqllab/test_requires_dataset_match.py - 3
Additional Suggestions - 4
  • superset/security/manager.py - 1
    • Duplicated error-msg builder · Line 2820-2838
      `get_dataset_match_access_error_msg` duplicates the structure of `get_table_access_error_msg` (both build `quoted_tables` and format a `%(tables)s` message). Extract the shared quoting/formatting into one helper so the two messages can't drift apart.
  • docs/admin_docs/security/security.mdx - 1
    • Doc overstates flag coverage · Line 72-72
      The doc lists SQL formatting as covered by `SQLLAB_REQUIRE_DATASET_MATCH`, but `SqllabApi.format_sql` (superset/sqllab/api.py:253) only calls `raise_for_access(..., force_dataset_match=requires_dataset_match())` inside `if template_params:`. Formatting without template_params performs no dataset/schema/catalog check at all, so the flag does not gate that case. Consider qualifying the claim.
  • tests/integration_tests/security_tests.py - 2
    • Missing local variable annotation · Line 1930-1930
      BITO.md rule 13347 mandates explicit type annotations on all local variables in test files, including inferable ones. The newly added `message` at line 1930 is unannotated; annotate it as `message: str = str(ctx.exception)` to comply with the project's typing standard.
    • Brittle i18n message assertions · Line 1931-1933
      These substring assertions match the `_()`-wrapped, translatable message built by `get_dataset_match_access_error_msg` (`superset/security/manager.py:2832`), so they break under a non-English test locale or future rewording. Asserting `ctx.exception.error.error_type` and `error.extra["tables"]` would be locale-independent and also pin the denied table.
Review Details
  • Files reviewed - 15 · Commit Range: d11f470..d11f470
    • docs/admin_docs/configuration/configuring-superset.mdx
    • docs/admin_docs/security/security.mdx
    • superset/commands/sql_lab/estimate.py
    • superset/config.py
    • superset/mcp_service/sql_lab/tool/execute_sql.py
    • superset/models/sql_lab.py
    • superset/security/manager.py
    • superset/sqllab/api.py
    • superset/sqllab/utils.py
    • superset/sqllab/validators.py
    • tests/integration_tests/security_tests.py
    • tests/unit_tests/commands/sql_lab/test_estimate.py
    • tests/unit_tests/security/manager_test.py
    • tests/unit_tests/sqllab/api_test.py
    • tests/unit_tests/sqllab/test_requires_dataset_match.py
  • Files skipped - 2
    • SECURITY.md - Reason: Filter setting
    • UPDATING.md - Reason: Filter setting
  • 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

Comment thread tests/unit_tests/sqllab/test_requires_dataset_match.py
Comment thread tests/unit_tests/sqllab/test_requires_dataset_match.py
Comment thread tests/unit_tests/sqllab/test_requires_dataset_match.py
@codecov

codecov Bot commented Oct 4, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 86.04651% with 6 lines in your changes missing coverage. Please review.
✅ Project coverage is 84.14%. Comparing base (d595bec) to head (bd07d47).
⚠️ Report is 34 commits behind head on master.

Files with missing lines Patch % Lines
superset/mcp_service/sql_lab/tool/execute_sql.py 73.91% 6 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##           master   #44968       +/-   ##
===========================================
+ Coverage   65.35%   84.14%   +18.78%     
===========================================
  Files        3057     3056        -1     
  Lines      201579   201522       -57     
  Branches    47149    47106       -43     
===========================================
+ Hits       131747   169568    +37821     
+ Misses      66866    28711    -38155     
- Partials     2966     3243      +277     
Flag Coverage Δ
hive 34.86% <34.88%> (+<0.01%) ⬆️
mysql 52.82% <46.51%> (?)
postgres 52.82% <46.51%> (?)
presto 36.60% <34.88%> (+<0.01%) ⬆️
python 87.38% <86.04%> (+34.68%) ⬆️
sqlite 52.59% <46.51%> (-0.01%) ⬇️
unit 81.79% <86.04%> (?)

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.

Comment thread superset/sqllab/validators.py
@pull-request-size pull-request-size Bot added size/XL and removed size/L labels Oct 4, 2026
@github-actions github-actions Bot added i18n Namespace | Anything related to localization i18n:spanish Translation related to Spanish language i18n:italian Translation related to Italian language labels Oct 4, 2026
@github-actions github-actions Bot added i18n:french Translation related to French language i18n:chinese Translation related to Chinese language i18n:japanese Translation related to Japanese language i18n:russian Translation related to Russian language i18n:korean Translation related to Korean language i18n:dutch i18n:slovak i18n:ukrainian i18n:portuguese i18n:brazilian i18n:traditional-chinese i18n:persian i18n:czech i18n:latvian labels Oct 4, 2026

@bito-code-review bito-code-review Bot 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.

Code Review Agent Run #483b91

Actionable Suggestions - 1
  • superset/mcp_service/sql_lab/tool/execute_sql.py - 1
Additional Suggestions - 15
  • superset/translations/ca/LC_MESSAGES/messages.po - 1
    • Empty Catalan translation · Line 20733-20739
      This new msgid (matching `manager.py:2833`) is added with an empty `msgstr ""`, so Catalan users will fall back to the English message. The surrounding backfilled entries carry real translations; this one is incomplete. Add the Catalan translation or drop the entry until it is ready.
  • superset/translations/de/LC_MESSAGES/messages.po - 1
    • Untranslated German msgstr · Line 19638-19644
      The new entry adds a German msgid but leaves `msgstr ""` empty, so German users will fall back to the English text from `superset/security/manager.py` (`get_table_access_error_message`). Fill in the German translation so the localized message is actually delivered.
  • superset/translations/zh/LC_MESSAGES/messages.po - 1
    • Empty translation msgstr · Line 20121-20121
      The new entry for the error message from `superset/security/manager.py:2833` has an empty `msgstr ""`. Chinese users will see the untranslated English text. Fill in the translation before merging.
  • superset/translations/fr/LC_MESSAGES/messages.po - 1
    • Missing French translation · Line 20017-20023
      The new msgid (matching `manager.py` `get_table_access_error_message`) is added with an empty `msgstr ""`, so French users will fall back to the English text. Provide a French translation to complete the localization for this new error message.
  • superset/translations/zh_TW/LC_MESSAGES/messages.po - 1
    • Empty translation msgstr · Line 21449-21449
      New entry's `msgstr` is empty, so zh_TW users see the untranslated English access-denied message from `manager.py:2833`. Per BITO rules [12743]/[13343], fill the msgstr with a verified Traditional Chinese translation before merging.
  • superset/translations/lv/LC_MESSAGES/messages.po - 1
    • Missing translation · Line 19643-19649
      Newly added msgid has an empty `msgstr ""`, so Latvian users will see the untranslated English text for this access-denied message. Fill in the Latvian translation before merging (BITO.md rule 12743).
  • superset/translations/es/LC_MESSAGES/messages.po - 1
    • Empty translation msgstr · Line 20613-20619
      The new entry's `msgstr` is empty, so Spanish users will see the English `msgid` (gettext falls back to the source string). The msgid matches `manager.py:2832` (`get_dataset_match_access_error_msg`) exactly and the `#, python-format` flag is correct, but the translation itself is missing. Fill in the Spanish `msgstr` to complete the entry.
  • superset/translations/pt_BR/LC_MESSAGES/messages.po - 1
    • Missing Portuguese translation · Line 21400-21406
      The new entry's `msgstr` is empty, so pt_BR users will fall back to the English source string from `manager.py` `get_table_access_error_message`. Since this entry was added to the translation file, provide the Portuguese translation to complete it.
  • superset/translations/ru/LC_MESSAGES/messages.po - 1
    • Empty translation msgstr · Line 19307-19307
      New user-facing error message (from `manager.py` `get_table_access_error_message`) is added with an empty `msgstr ""`, so Russian users will see the untranslated English text. Neighboring entries (e.g. line 19298) are translated. Fill in the Russian translation before merging.
  • superset/translations/th/LC_MESSAGES/messages.po - 1
    • Empty Thai translation · Line 32017-32017
      This new entry adds the datasource_access error message (from `manager.py:2833`) but leaves `msgstr ""` empty. Thai users will see the raw English error instead of a translation. Per BITO.md rules 12743/13343, fill in the Thai `msgstr` before merging.
  • superset/translations/ar/LC_MESSAGES/messages.po - 1
    • Missing Arabic translation · Line 21337-21337
      The new entry's `msgstr` is empty, so Arabic users will see the untranslated English error text. The msgid matches the source string in `manager.py` `get_table_access_error_object`. Fill in the Arabic translation before merging (BITO.md rules 12743/13343).
  • superset/translations/cs/LC_MESSAGES/messages.po - 1
    • Missing Czech translation · Line 20015-20015
      The newly added msgid (matching `manager.py:2832` `get_table_access_error_message`) has an empty `msgstr`, so Czech users will see the English fallback for this access-denied message. Add the Czech translation so the new string is actually localized.
  • superset/translations/ro/LC_MESSAGES/messages.po - 1
    • Empty msgstr translation · Line 20955-20955
      New entry for the error message from `superset/security/manager.py:2833` is added with an empty `msgstr ""`, so Romanian users will see the untranslated English text. Per BITO rules 13343/12743, user-facing error messages must have complete translations before merge. Please fill and verify the Romanian `msgstr`.
  • superset/translations/pl/LC_MESSAGES/messages.po - 1
    • Missing Polish translation · Line 21706-21706
      The new msgid (matching `manager.py:2833`) is added with an empty `msgstr`, so Polish users will see the English fallback for this permission-denied message. Provide the Polish translation to complete the localization.
  • tests/unit_tests/commands/sql_lab/test_estimate.py - 1
    • Fragile call index · Line 235-235
      `call_args_list[1]` hardcodes the assumption that exactly two `raise_for_access` calls occur, in a fixed order (validate's source check, then run's rendered check). If `validate()` ever adds another authorization call, this index silently selects the wrong call and the test fails confusingly. `call_args_list[-1]` is equally clear and robust to call-count changes.
Filtered by Review Rules

Bito filtered these suggestions based on rules created automatically for your feedback. Manage rules.

  • superset/translations/fi/LC_MESSAGES/messages.po - 1
  • superset/translations/tr/LC_MESSAGES/messages.po - 1
Review Details
  • Files reviewed - 43 · Commit Range: d11f470..10892e9
    • docs/admin_docs/configuration/configuring-superset.mdx
    • docs/admin_docs/security/security.mdx
    • superset/config.py
    • superset/sqllab/utils.py
    • superset/commands/sql_lab/estimate.py
    • tests/unit_tests/commands/sql_lab/test_estimate.py
    • superset/mcp_service/sql_lab/tool/execute_sql.py
    • tests/unit_tests/mcp_service/sql_lab/tool/test_execute_sql.py
    • tests/unit_tests/sqllab/test_requires_dataset_match.py
    • superset/security/manager.py
    • tests/unit_tests/security/manager_test.py
    • superset/translations/ar/LC_MESSAGES/messages.po
    • superset/translations/ca/LC_MESSAGES/messages.po
    • superset/translations/cs/LC_MESSAGES/messages.po
    • superset/translations/de/LC_MESSAGES/messages.po
    • superset/translations/en/LC_MESSAGES/messages.po
    • superset/translations/es/LC_MESSAGES/messages.po
    • superset/translations/fa/LC_MESSAGES/messages.po
    • superset/translations/fi/LC_MESSAGES/messages.po
    • superset/translations/fr/LC_MESSAGES/messages.po
    • superset/translations/it/LC_MESSAGES/messages.po
    • superset/translations/ja/LC_MESSAGES/messages.po
    • superset/translations/ko/LC_MESSAGES/messages.po
    • superset/translations/lv/LC_MESSAGES/messages.po
    • superset/translations/messages.pot
    • superset/translations/mi/LC_MESSAGES/messages.po
    • superset/translations/nl/LC_MESSAGES/messages.po
    • superset/translations/pl/LC_MESSAGES/messages.po
    • superset/translations/pt/LC_MESSAGES/messages.po
    • superset/translations/pt_BR/LC_MESSAGES/messages.po
    • superset/translations/ro/LC_MESSAGES/messages.po
    • superset/translations/ru/LC_MESSAGES/messages.po
    • superset/translations/sk/LC_MESSAGES/messages.po
    • superset/translations/sl/LC_MESSAGES/messages.po
    • superset/translations/sr/LC_MESSAGES/messages.po
    • superset/translations/sr_Latn/LC_MESSAGES/messages.po
    • superset/translations/ta/LC_MESSAGES/messages.po
    • superset/translations/th/LC_MESSAGES/messages.po
    • superset/translations/tr/LC_MESSAGES/messages.po
    • superset/translations/uk/LC_MESSAGES/messages.po
    • superset/translations/zh/LC_MESSAGES/messages.po
    • superset/translations/zh_TW/LC_MESSAGES/messages.po
    • tests/unit_tests/subjects/test_raise_for_access.py
  • Files skipped - 2
    • SECURITY.md - Reason: Filter setting
    • UPDATING.md - Reason: Filter setting
  • 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

Comment thread superset/mcp_service/sql_lab/tool/execute_sql.py
@github-actions github-actions Bot added the requires:rebase Requires rebasing on top of current master label Oct 8, 2026
…ccess-opt-out

Co-authored-by: Cursor <cursoragent@cursor.com>
@codeant-ai-for-open-source

codeant-ai-for-open-source Bot commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

CodeAnt PR Risk: Low Risk

  • The PR appears safe to merge; the reported SQL Lab authorization gaps are addressed in the current code.
  • Cost estimation and MCP execution now authorize the rendered SQL they actually use, with tests covering these checks.

Assessed commit: bd07d47ee9c2

@github-actions github-actions Bot added requires:rebase Requires rebasing on top of current master and removed requires:rebase Requires rebasing on top of current master labels Oct 21, 2026
AmoghAtreya and others added 2 commits October 22, 2026 13:41
…ccess-opt-out

Co-authored-by: Cursor <cursoragent@cursor.com>
…ccess-opt-out

Co-authored-by: Cursor <cursoragent@cursor.com>
@github-actions github-actions Bot added requires:rebase Requires rebasing on top of current master and removed requires:rebase Requires rebasing on top of current master labels Oct 23, 2026

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

api Related to the REST API doc Namespace | Anything related to documentation i18n:brazilian i18n:chinese Translation related to Chinese language i18n:czech i18n:dutch i18n:french Translation related to French language i18n:italian Translation related to Italian language i18n:japanese Translation related to Japanese language i18n:korean Translation related to Korean language i18n:latvian i18n:persian i18n:portuguese i18n:russian Translation related to Russian language i18n:slovak i18n:spanish Translation related to Spanish language i18n:traditional-chinese i18n:ukrainian i18n Namespace | Anything related to localization requires:rebase Requires rebasing on top of current master size/XL

Projects

None yet

Development

Successfully merging this pull request may close these issues.

SQL Lab denies queries for users with schema_access/catalog_access (regression after #40409); no way to opt out

2 participants