Skip to content

feat(mcp): scope embedded-guest data reads to the token's dashboards#41753

Merged
gabotorresruiz merged 1 commit into
apache:masterfrom
gabotorresruiz:feat/mcp-embedded-guest-data-read
Jul 9, 2026
Merged

feat(mcp): scope embedded-guest data reads to the token's dashboards#41753
gabotorresruiz merged 1 commit into
apache:masterfrom
gabotorresruiz:feat/mcp-embedded-guest-data-read

Conversation

@gabotorresruiz

@gabotorresruiz gabotorresruiz commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

SUMMARY

Lets an embedded guest (an anonymous dashboard viewer authenticated by a guest token) read chart data over the MCP service, scoped to the dashboards in their guest token, so an embedded assistant can analyze the dashboard the viewer is looking at, and nothing else.

Before this change a guest could read dashboard structure but get_chart_data, get_chart_info, and get_chart_preview failed ("Chart not found" / dataset not accessible): ChartFilter had no embedded-guest branch (only DashboardAccessFilter did), and the data path needs the embedded dashboard context for raise_for_access.

Design (mirrors the existing embedded-dashboard pattern, no new bespoke security path):

  • Resolution scoping lives in the access filter. New shared helper guest_embedded_dashboard_filter() (superset/utils/filters.py) builds a SQLAlchemy condition matching the guest token's embedded dashboards, mirroring DashboardAccessFilter. ChartFilter gains a guest branch that scopes chart resolution to charts on those dashboards.
  • Data-query authorization reuses core's existing guest raise_for_access branch. New superset/mcp_service/guest_scope.py attaches the embedded dashboard context (dashboardId / slice_id) to the query, exactly as the embedded frontend does, and pins slice_ so the guest payload tamper-guard (query_context_modified) still compares requested columns/metrics against the resolved chart. The three read tools skip the dataset RBAC pre-check for guests (guests read via the dashboard context, not dataset RBAC; raise_for_access remains the real gate).
  • Contained to the embedded-guest path. guest_dashboard_id() short-circuits on is_guest_user(), so behavior for regular authenticated users is unchanged.
  • Row-level security, dataset allow-list, and dashboard access continue to be enforced by core's raise_for_access; guests only reach their token's resources.

This is the data-read scoping layer. The guest-token authentication that resolves the GuestUser over MCP lands in #41003, this PR depends on #41003 for end-to-end function (the code is dormant until that merges; the diff itself is
independent and reviews/merges standalone).

BEFORE/AFTER SCREENSHOTS OR ANIMATED GIF

N/A. Backend-only change (MCP read-tool authorization); no UI

TESTING INSTRUCTIONS

Requires EMBEDDED_SUPERSET and (for the guest to authenticate over MCP) MCP_EMBEDDED_GUEST_AUTH_ENABLED from #41003.

  1. Mint a guest token scoped to an embedded dashboard (e.g. via the guest-token endpoint) and present it as Authorization: Bearer <guest_token>.
  2. Call get_chart_data / get_chart_info / get_chart_preview for a chart on that dashboard --> returns the chart's data/metadata/preview.
  3. Call the same tools for a chart not on the token's dashboard --> not found (out of scope), with no leak.
  4. Confirm any RLS rules on the guest token still constrain returned rows.
  5. Confirm a regular authenticated (non-guest) user's results are unchanged (dataset access check still runs; no dashboard context attached).

ADDITIONAL INFORMATION

  • Has associated issue:
  • Required feature flags: EMBEDDED_SUPERSET
  • 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

@gabotorresruiz gabotorresruiz force-pushed the feat/mcp-embedded-guest-data-read branch from 1c19f36 to 07da628 Compare July 3, 2026 18:44
@codecov

codecov Bot commented Jul 3, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 20.80000% with 99 lines in your changes missing coverage. Please review.
✅ Project coverage is 64.57%. Comparing base (afc7dbe) to head (d443dea).

Files with missing lines Patch % Lines
superset/mcp_service/auth.py 16.00% 21 Missing ⚠️
superset/mcp_service/guest_scope.py 25.92% 20 Missing ⚠️
superset/mcp_service/chart/tool/get_chart_data.py 10.52% 17 Missing ⚠️
superset/utils/filters.py 37.50% 14 Missing and 1 partial ⚠️
...perset/mcp_service/chart/tool/get_chart_preview.py 11.11% 8 Missing ⚠️
superset/mcp_service/chart/tool/get_chart_info.py 0.00% 3 Missing ⚠️
superset/mcp_service/chart/tool/get_chart_sql.py 0.00% 3 Missing ⚠️
...perset/mcp_service/rls/tool/get_rls_filter_info.py 0.00% 3 Missing ⚠️
superset/mcp_service/rls/tool/list_rls_filters.py 0.00% 3 Missing ⚠️
superset/charts/filters.py 33.33% 1 Missing and 1 partial ⚠️
... and 2 more
Additional details and impacted files
@@            Coverage Diff             @@
##           master   #41753      +/-   ##
==========================================
- Coverage   64.60%   64.57%   -0.04%     
==========================================
  Files        2712     2713       +1     
  Lines      151168   151269     +101     
  Branches    34769    34793      +24     
==========================================
+ Hits        97665    97677      +12     
- Misses      51680    51764      +84     
- Partials     1823     1828       +5     
Flag Coverage Δ
hive 39.01% <16.80%> (-0.04%) ⬇️
mysql 57.43% <20.80%> (-0.06%) ⬇️
postgres 57.49% <20.80%> (-0.06%) ⬇️
presto 40.52% <20.80%> (-0.04%) ⬇️
python 58.90% <20.80%> (-0.07%) ⬇️
sqlite 57.08% <20.80%> (-0.06%) ⬇️
unit 100.00% <ø> (ø)

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.

@gabotorresruiz gabotorresruiz force-pushed the feat/mcp-embedded-guest-data-read branch from 07da628 to 00837c5 Compare July 3, 2026 18:59
@gabotorresruiz gabotorresruiz marked this pull request as ready for review July 3, 2026 19:25
@dosubot dosubot Bot added authentication Related to authentication change:backend Requires changing the backend embedded labels Jul 3, 2026
@github-actions

github-actions Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

⚠️ Translation Regression Detected

A source change in this PR renamed or reworded strings, invalidating existing translations (they are now #, fuzzy) in fr. Please resolve the affected .po files before merging.

Note: neither intentionally deleting a translatable string nor filling a previously-untranslated entry with a fuzzy guess (e.g. an AI backfill) is a regression — only a confirmed translation that a renamed/reworded source string turned fuzzy is flagged here.

Language Invalidated translations
fr 89

How to fix

1. Install dependencies (if not already set up):

pip install -r superset/translations/requirements.txt
sudo apt-get install gettext   # or: brew install gettext

2. Re-extract strings and sync .po files:

./scripts/translations/babel_update.sh

This rewrites superset/translations/messages.pot from the current source files and merges the changes into every .po file. Strings whose msgid changed will be marked #, fuzzy.

3. Resolve the fuzzy entries in the affected language files (fr):

grep -n '#, fuzzy' superset/translations/<lang>/LC_MESSAGES/messages.po

For each fuzzy entry, either rewrite the msgstr to match the new string and remove the #, fuzzy line, or clear the msgstr to "" if you cannot provide a translation.

4. Commit your changes to the .po files.

@gabotorresruiz gabotorresruiz force-pushed the feat/mcp-embedded-guest-data-read branch from 00837c5 to 6fa7814 Compare July 3, 2026 19:34
@github-actions github-actions Bot removed the embedded label Jul 3, 2026
@bito-code-review

bito-code-review Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Code Review Agent Run #bea91a

Actionable Suggestions - 0
Additional Suggestions - 2
  • superset/mcp_service/chart/tool/get_chart_preview.py - 1
    • Missing test for guest auth path · Line 1257-1264
      No test covers the new guest-authorization path in `get_chart_preview`. Per BITO.md rule 6262 (adaptive_rules), tests should verify the business logic they claim to cover — the new guest bypass of `validate_chart_dataset` at lines 1257-1264 is not exercised.
  • superset/mcp_service/chart/tool/get_chart_info.py - 1
    • Import placement at function scope · Line 108-108
      The `security_manager` import inside `_validate_chart_dataset_access` is repeated on every function call. Moving it to module level (alongside the existing `validate_chart_dataset` import from chart_utils) would follow Superset conventions and avoid redundant module resolution overhead.
Review Details
  • Files reviewed - 8 · Commit Range: 6fa7814..6fa7814
    • superset/charts/filters.py
    • superset/mcp_service/chart/tool/get_chart_data.py
    • superset/mcp_service/chart/tool/get_chart_info.py
    • superset/mcp_service/chart/tool/get_chart_preview.py
    • superset/mcp_service/guest_scope.py
    • superset/utils/filters.py
    • tests/unit_tests/mcp_service/test_guest_scope.py
    • tests/unit_tests/utils/filters_test.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 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

@aminghadersohi aminghadersohi 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.

Security-focused review of the embedded-guest chart-data scoping mechanism (get_chart_data/get_chart_info/get_chart_preview + ChartFilter/guest_scope.py). Not approving — security-boundary PR, approval held for a human.

Design verdict for the 3 tools this PR touches: sound. Verified (not assumed) that resolution is WHERE-scoped at the SQL layer — ChartDAO.base_filter = ChartFilter, and BaseDAO.find_by_id/_find_by_column always apply base_filter unless explicitly skipped (find_chart_by_identifier never skips it) — so an out-of-scope chart never resolves for a guest; it isn't a fetch-then-drop pattern. The guest_scope.authorize_query() dashboard-context hand-off is correct defense-in-depth on top of that: core's raise_for_access() guest branch (superset/security/manager.py) re-derives the dashboard from form_data["dashboardId"] and re-validates via can_access_dashboard()has_guest_access(), so a forged/stale dashboardId can't grant access to a dashboard outside the token. Non-guest behavior confirmed unaffected in all 4 touched files (each guest branch short-circuits via is_guest_user()/get_current_guest_user_if_guest() returning falsy for real users).

HIGH — gate completeness gap outside this PR's 3 tools (no diff line; files not touched by this PR). superset/mcp_service/dataset/tool/query_dataset.py, get_dataset_info.py, and list_datasets.py resolve via DatasetDAO (base_filter = DatasourceFilter) and never touch guest_scope or attach dashboardId/slice_id. They currently deny guests only incidentallyDatasourceFilter falls through to schema_perm/catalog_perm RBAC matching, which an ephemeral guest role happens to match nothing against — not via any explicit guest-dashboard check. query_dataset.py additionally logs the dataset name and diffs requested columns/metrics against the real schema before any raise_for_access call, so if resolution ever succeeds for a guest (a guest/Public role with schema-level grants is a realistic embedded-analytics config, or any future loosening of DatasourceFilter), this tool discloses schema ahead of the auth check this PR's design otherwise routes everything through. Recommend applying the same guest_scope pattern (or an explicit is_guest_user() guard returning a clean 403) to these three tools before/alongside #41003 landing. (list_charts.py is fine — it goes through ChartDAO/ChartFilter and is fixed by this PR as a side effect.)

MEDIUM — get_chart_sql.py wasn't given the same treatment (superset/mcp_service/chart/tool/get_chart_sql.py:413, not touched by this PR). Chart resolution there is already guest-scoped via the same ChartFilter, but it still unconditionally calls validate_chart_dataset(chart, check_access=True) — the exact dataset-RBAC pre-check this PR bypasses for guests elsewhere. A guest requesting SQL for a chart genuinely on their dashboard gets DatasetNotAccessible instead. Fails closed (no leak), but looks like an oversight vs. an intentional exclusion.

Line-specific items inline below. Scan coverage: manual systematic pass (injection/authz-bypass/error-oracle/DRY/test-coverage/secrets/boolean-traps) across all 6 non-test changed files plus the unchanged core methods this PR depends on and the other 14 guest-reachable read tools under superset/mcp_service/**/tool/.

Comment thread superset/charts/filters.py
Comment thread superset/mcp_service/guest_scope.py
Comment thread superset/mcp_service/chart/tool/get_chart_data.py Outdated
@gabotorresruiz gabotorresruiz force-pushed the feat/mcp-embedded-guest-data-read branch from 6fa7814 to 87a8a18 Compare July 6, 2026 18:41
@pull-request-size pull-request-size Bot added size/XL and removed size/L labels Jul 6, 2026
Comment thread superset/charts/filters.py
Comment thread superset/mcp_service/chart/tool/get_chart_data.py
Comment thread superset/mcp_service/guest_scope.py
Comment thread superset/utils/filters.py Outdated
Comment thread tests/unit_tests/charts/test_filters.py Outdated
Comment thread tests/unit_tests/charts/test_filters.py Outdated
Comment thread tests/unit_tests/charts/test_filters.py Outdated
@gabotorresruiz gabotorresruiz force-pushed the feat/mcp-embedded-guest-data-read branch from 87a8a18 to ec8d907 Compare July 6, 2026 18:46
Comment thread superset/charts/filters.py
@gabotorresruiz gabotorresruiz force-pushed the feat/mcp-embedded-guest-data-read branch 2 times, most recently from 497e171 to 0e932c4 Compare July 6, 2026 18:58
@netlify

netlify Bot commented Jul 6, 2026

Copy link
Copy Markdown

Deploy Preview for superset-docs-preview ready!

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

@aminghadersohi aminghadersohi 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.

Round 2 re-review at HEAD 0e932c41 (rebased/force-pushed since the last review at 6fa78143). CI green. Not approving — security-boundary PR, sign-off held for a human.

Resolved from round 1 (verified, not just re-read):

  • The ChartFilter guest branch now has direct test coverage — new tests/unit_tests/charts/test_filters.py exercises ChartFilter.apply() itself (not just the leaf helpers): confirms the guest branch is taken and short-circuits before the datasource-access join, confirms non-guests reach the original join path, confirms admin/can_access_all_datasources bypasses everything. Deleting the guest branch now fails a real test.
  • The "skip dataset RBAC pre-check for guests" predicate, previously reimplemented 3 different ways, is now a single guest_scope.is_guest_read() helper used consistently across get_chart_data.py, get_chart_info.py, and get_chart_preview.py. Traced through: this only controls a redundant pre-check skip, not the actual gate — the real authorization (raise_for_access via authorize_query()/command.validate()) is unchanged and still keyed off the per-chart guest_dashboard_id(chart) value, so this simplification doesn't weaken anything.
  • The row_limit int-coercion is now a named _coerce_row_limit() helper with a dedicated parametrized test (6 cases). No longer scope creep — it's a tested utility.

Still open from round 1 (unaddressed by this push — files untouched):

  • HIGH: query_dataset.py / get_dataset_info.py / list_datasets.py under superset/mcp_service/dataset/tool/ still have no guest-aware scoping (confirmed — no reference to guest_scope, is_guest_user, or raise_for_access context-attachment in any of them at this HEAD).
  • MEDIUM: get_chart_sql.py still unconditionally calls validate_chart_dataset(chart, check_access=True) (line 414) without the guest_scope.is_guest_read() skip the other three chart tools now share — an embedded guest still can't read SQL for a chart genuinely on their own dashboard.

New, independently confirmed: codeant's finding on superset/charts/filters.py (mixed UUID + integer dashboard IDs in a guest token push non-UUID values into EmbeddedDashboard.uuid.in_(...), a UUID-typed column) is correct — traced guest_embedded_dashboard_filter() and confirmed it routes the entire mixed ids list through the UUID branch whenever any single ID looks like a UUID. That's a real runtime bind/type-conversion error for a mixed-ID guest token (fails closed/500, not a leak, but a genuine availability bug during the uuid-migration window). Already an open thread from codeant — not re-filing, just corroborating with attribution so it doesn't get lost.

@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 #341acc

Actionable Suggestions - 2
  • superset/mcp_service/chart/tool/get_chart_info.py - 1
  • superset/mcp_service/chart/tool/get_chart_preview.py - 1
Review Details
  • Files reviewed - 10 · Commit Range: 0e932c4..0e932c4
    • superset/charts/filters.py
    • superset/mcp_service/chart/tool/get_chart_data.py
    • superset/mcp_service/chart/tool/get_chart_info.py
    • superset/mcp_service/chart/tool/get_chart_preview.py
    • superset/mcp_service/guest_scope.py
    • superset/utils/filters.py
    • tests/unit_tests/charts/test_filters.py
    • tests/unit_tests/mcp_service/chart/tool/test_get_chart_data.py
    • tests/unit_tests/mcp_service/test_guest_scope.py
    • tests/unit_tests/utils/filters_test.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 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/chart/tool/get_chart_info.py
Comment thread superset/mcp_service/chart/tool/get_chart_preview.py
@gabotorresruiz gabotorresruiz force-pushed the feat/mcp-embedded-guest-data-read branch from 0e932c4 to 1d5ed2e Compare July 7, 2026 15:28
@gabotorresruiz gabotorresruiz force-pushed the feat/mcp-embedded-guest-data-read branch from 94ff233 to 4a42d82 Compare July 7, 2026 19:19

@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 #0a1301

Actionable Suggestions - 3
  • superset/mcp_service/guest_scope.py - 2
    • Replace Any type annotation in guest_dashboard_id · Line 44-44
    • Replace Any type annotations in authorize_query · Line 57-57
  • superset/utils/filters.py - 1
Filtered by Review Rules

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

  • superset/mcp_service/chart/tool/get_chart_data.py - 1
  • tests/unit_tests/mcp_service/chart/tool/test_get_chart_info.py - 2
Review Details
  • Files reviewed - 20 · Commit Range: 4a42d82..4a42d82
    • superset/charts/filters.py
    • superset/mcp_service/auth.py
    • superset/mcp_service/chart/tool/get_chart_data.py
    • superset/mcp_service/chart/tool/get_chart_info.py
    • superset/mcp_service/chart/tool/get_chart_preview.py
    • superset/mcp_service/chart/tool/get_chart_sql.py
    • superset/mcp_service/guest_scope.py
    • superset/mcp_service/mcp_config.py
    • superset/mcp_service/rls/tool/get_rls_filter_info.py
    • superset/mcp_service/rls/tool/list_rls_filters.py
    • superset/utils/filters.py
    • tests/unit_tests/charts/test_filters.py
    • tests/unit_tests/mcp_service/chart/tool/test_get_chart_data.py
    • tests/unit_tests/mcp_service/chart/tool/test_get_chart_info.py
    • tests/unit_tests/mcp_service/chart/tool/test_get_chart_preview.py
    • tests/unit_tests/mcp_service/chart/tool/test_get_chart_sql.py
    • tests/unit_tests/mcp_service/rls/tool/test_rls_tools.py
    • tests/unit_tests/mcp_service/test_guest_scope.py
    • tests/unit_tests/mcp_service/test_guest_token_auth.py
    • tests/unit_tests/utils/filters_test.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 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/guest_scope.py
Comment thread superset/mcp_service/guest_scope.py
Comment thread superset/utils/filters.py Outdated

@aminghadersohi aminghadersohi 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.

Round 4 re-review at HEAD 4a42d828 (rebased again, and this push is substantially larger — 10 → 20 files, +561/-33+736/-42). CI green. Not approving — security-boundary PR, sign-off held for a human.

Scope note: this push pulls in real machinery from #41003 (superset/mcp_service/auth.py, mcp_config.py — the MCP_GUEST_DENIED_TOOLS deny-list + check_tool_permission's class_permission_name RBAC gate) that wasn't part of my earlier rounds. I read it in full this round rather than treating it as out-of-scope background, since it materially changes the answer to "is a given MCP tool actually guest-reachable."

Resolved this round:

  • MEDIUM from round 1 (get_chart_sql.py not guest-scoped) — now explicitly denies guests (if security_manager.is_guest_user(): return ChartError(..., error_type="Forbidden")), matching the same reasoning as get_dataset_info ("exposes tables/columns/joins"). Simpler than scoping, and safe. Backed by a real end-to-end test (test_guest_denied, via an actual Client(mcp_server).call_tool(...)).
  • Two new RLS tools (get_rls_filter_info.py, list_rls_filters.py) are explicitly guest-denied the same way, each with an end-to-end test.
  • The default guest tool deny-list (_DEFAULT_GUEST_DENIED_TOOLS / MCP_GUEST_DENIED_TOOLS) grew from 2 to 6 entries (get_role_info, get_user_info, list_roles, list_users added), with a new test asserting the two lists stay in sync and a parametrized test confirming every entry is actually blocked.
  • Both NITs bito raised last round (missing direct tests for the is_guest_read()/guest_dashboard_id() skips in get_chart_info.py and get_chart_preview.py) are now covered by dedicated tests.

This is a genuinely systematic hardening pass across the guest-reachable tool surface — good pattern, applied consistently 3 times this round alone.

Still open, and now more urgent given what I learned about the gate architecture — HIGH: query_dataset.py / get_dataset_info.py / list_datasets.py remain the only unclosed items in this sweep. All three declare class_permission_name="Dataset", so their only guest gate is check_tool_permission's generic RBAC check: security_manager.can_access("can_read", "Dataset") against whatever role GuestUser.roles resolves to — which is GUEST_ROLE_NAME (default "Public", per superset/config.py). If PUBLIC_ROLE_LIKE is configured to grant that role broad read access — a common, arguably expected pattern for embedded-analytics deployments, since without it Public/guest gets zero menu access — this RBAC check passes, the tool body runs, and a guest can read any dataset by id, completely unscoped to their token's dashboards. That defeats this PR's stated purpose. Given the exact fix pattern was just applied 3 times in this same push (inline is_guest_user()Forbidden, or add the 3 tool names to MCP_GUEST_DENIED_TOOLS), closing this should be quick — it's the last gap in an otherwise complete pass, not a new design problem.

Still escalating to Amin for final sign-off regardless of how this resolves, per this author's established MCP-PR pattern.

@gabotorresruiz gabotorresruiz force-pushed the feat/mcp-embedded-guest-data-read branch from 4a42d82 to 1c3e66d Compare July 7, 2026 23:28
@gabotorresruiz gabotorresruiz force-pushed the feat/mcp-embedded-guest-data-read branch from 1c3e66d to 1819c18 Compare July 7, 2026 23:36

@aminghadersohi aminghadersohi 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.

Round 5 re-review at HEAD 1819c18b (10→27 files across rounds, +736/-42+1030/-98). CI green, no new bot/reviewer activity since round 4. Not approving — security-boundary PR, sign-off held for a human (policy unchanged regardless of how clean this is).

The round-4 HIGH is resolved, and resolved better than what I asked for. Rather than adding query_dataset/get_dataset_info/list_datasets to a per-tool deny-list, this round flips the entire guest gate from deny-list to default-deny allow-list: MCP_GUEST_ALLOWED_TOOLS (auth.py's _tool_denied_for_principal + mcp_config.py) now permits a guest to call only get_dashboard_info / get_dashboard_layout / list_dashboards / list_charts / get_chart_info / get_chart_data / get_chart_preview — everything else, including the 3 dataset tools and any tool added in the future, is denied unless explicitly allow-listed. This structurally closes the class of bug ("a new/overlooked tool falls open to guests") rather than just the 3 instances I named. Verified with a parametrized test (test_non_allow_listed_tools_denied_to_guest) that explicitly covers get_dataset_info, list_datasets, query_dataset, plus 19 other tools across data-model/mutating/enumeration categories — this is exactly the regression test I'd have asked for.

Two more things I'd flagged (one as an open HIGH's underlying risk, one from round 3) are also independently closed, at the right layer:

  • superset/mcp_service/privacy.py's user_can_view_data_model_metadata() now denies guests unconditionally, before the RBAC can_access check — with a comment stating the exact scenario I raised in round 4 ("a PUBLIC_ROLE_LIKE=Gamma guest carries can_get_drill_info on Dataset, which would otherwise pass"). Backed by a test (test_user_can_view_data_model_metadata_denies_guest) that mocks can_access to return True and asserts the guest is still denied — proving the short-circuit actually overrides a permissive RBAC grant, not just that it runs first.
  • superset/security/manager.py's validate_guest_token_resources() now rejects a raw integer dashboard id at token issuance if that dashboard isn't actually embedded (elif not dashboard.embedded: raise EmbeddedDashboardNotFoundError()). This closes the round-3 finding (int-id branch not checking .embedded, mirrored from the pre-existing DashboardAccessFilter) at its root — a guest token can no longer be minted against a non-embedded dashboard via the int-id path in the first place, which is a better fix than patching every read site individually.

I don't have any open findings from my side at this point across all 5 rounds. Escalating to Amin for final sign-off per this author's established MCP-security-PR policy — not a reflection on this round's quality, just standing policy for this class of change.

@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 #721a05

Actionable Suggestions - 1
  • superset/mcp_service/chart/tool/get_chart_data.py - 1
Filtered by Review Rules

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

  • tests/unit_tests/security/manager_test.py - 1
  • tests/unit_tests/mcp_service/chart/tool/test_get_chart_sql.py - 1
Review Details
  • Files reviewed - 26 · Commit Range: 1819c18..1819c18
    • superset/charts/filters.py
    • superset/mcp_service/auth.py
    • superset/mcp_service/chart/tool/get_chart_data.py
    • superset/mcp_service/chart/tool/get_chart_info.py
    • superset/mcp_service/chart/tool/get_chart_preview.py
    • superset/mcp_service/chart/tool/get_chart_sql.py
    • superset/mcp_service/guest_scope.py
    • superset/mcp_service/mcp_config.py
    • superset/mcp_service/privacy.py
    • superset/mcp_service/rls/tool/get_rls_filter_info.py
    • superset/mcp_service/rls/tool/list_rls_filters.py
    • superset/security/manager.py
    • superset/utils/filters.py
    • tests/unit_tests/charts/test_filters.py
    • tests/unit_tests/mcp_service/chart/tool/test_get_chart_data.py
    • tests/unit_tests/mcp_service/chart/tool/test_get_chart_info.py
    • tests/unit_tests/mcp_service/chart/tool/test_get_chart_preview.py
    • tests/unit_tests/mcp_service/chart/tool/test_get_chart_sql.py
    • tests/unit_tests/mcp_service/chart/tool/test_list_charts.py
    • tests/unit_tests/mcp_service/rls/tool/test_rls_tools.py
    • tests/unit_tests/mcp_service/system/tool/test_get_current_user.py
    • tests/unit_tests/mcp_service/test_guest_scope.py
    • tests/unit_tests/mcp_service/test_guest_token_auth.py
    • tests/unit_tests/mcp_service/test_privacy.py
    • tests/unit_tests/security/manager_test.py
    • tests/unit_tests/utils/filters_test.py
  • Files skipped - 2
    • superset/mcp_service/CLAUDE.md - Reason: Filter setting
    • superset/mcp_service/SECURITY.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 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 on lines +414 to +430
# Skip the dataset RBAC pre-check for guests (see guest_scope.is_guest_read).
if not guest_scope.is_guest_read():
validation_result = validate_chart_dataset(chart, check_access=True)
if not validation_result.is_valid:
await ctx.warning(
"Chart found but dataset is not accessible: %s"
% (validation_result.error,)
)
return ChartError(
error=validation_result.error
or "Chart's dataset is not accessible. "
"Dataset may have been deleted.",
error_type="DatasetNotAccessible",
)
# Log any warnings (e.g., virtual dataset warnings)
for warning in validation_result.warnings:
await ctx.warning("Dataset warning: %s" % (warning,))

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.

Missing guest scope integration test

The new guest-scoped bypass of validate_chart_dataset (line 414-430) and the authorize_query call (line 628-629) lack test coverage in tests/unit_tests/mcp_service/chart/tool/test_get_chart_data.py. An async integration test that mocks guest_scope.is_guest_read() to return True would verify the end-to-end guest flow: chart lookup → guest_dashboard_id capture → RBAC skip → authorize_query with dashboard context.

Code Review Run #721a05


Should Bito avoid suggestions like this for future reviews? (Manage Rules)

  • Yes, avoid them

@gabotorresruiz gabotorresruiz force-pushed the feat/mcp-embedded-guest-data-read branch from 1819c18 to bc82880 Compare July 8, 2026 19:07
Comment thread superset/utils/filters.py
Comment on lines +76 to +77
uuid_ids = [id_ for id_ in ids if is_uuid(id_)]
int_ids = [id_ for id_ in ids if not is_uuid(id_)]

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: Add explicit type annotations for the newly introduced local lists that separate UUID and integer dashboard identifiers. [custom_rule]

Severity Level: Minor ⚠️

Why it matters? 🤔

The new local variables uuid_ids and int_ids are list-valued and can be explicitly annotated (for example, as list[Any] or a more specific list type). Since the custom rule requires type hints for new or modified Python code where relevant variables can be annotated, omitting annotations here is a real violation.

Rule source 📖

.cursor/rules/dev-standard.mdc (line 28)

Fix in Cursor Fix in VSCode Claude

(Use Cmd/Ctrl + Click for best experience)

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

**Path:** superset/utils/filters.py
**Line:** 76:77
**Comment:**
	*Custom Rule: Add explicit type annotations for the newly introduced local lists that separate UUID and integer dashboard identifiers.

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

Comment thread tests/unit_tests/charts/test_filters.py
Comment thread tests/unit_tests/mcp_service/chart/tool/test_get_chart_sql.py
Comment thread superset/charts/filters.py
Comment thread superset/mcp_service/chart/tool/get_chart_data.py
Comment thread superset/charts/filters.py
Comment thread superset/mcp_service/auth.py

@aminghadersohi aminghadersohi 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.

Round 6 re-review at HEAD bc82880c. This PR's own authored diff is unchanged from round 5 (+1030/-98, identical files/hunks) — this push is a rebase onto a newer master that happens to include a large, unrelated upstream refactor (Owner/Editor/Viewer + a new "Subject" abstraction unifying users/roles/groups, RLS filters keyed by subjects instead of roles, Group API changes). None of that is this PR's content; confirmed by diffing this round's scoped gh pr diff against round 5's byte-for-byte — the only difference is context-line shifts and one mechanical rebase artifact (see below). All 5 rounds of findings remain resolved — 0 new security findings.

However, CI is now red on a required check (unit-tests-required), and it's worth understanding why before merging: tests/unit_tests/charts/test_filters.py::test_chart_filter_non_guest_skips_guest_branch fails with AttributeError: user at flask/ctx.py:54. Root cause: the rebase's unrelated upstream refactor changed ChartFilter.apply()'s non-guest tail from an inline query.join(...) call to return self._apply_viewers(query), and _apply_viewers() now calls get_user_id() (which touches g.user) before it does anything resembling a join. This test's technique — making query.join raise a sentinel RuntimeError to prove the non-guest path was reached — no longer works, because the refactored code hits the unmocked g.user access and raises AttributeError before ever calling query.join().

This is not a security regression — the guest branch itself (if (guest_dashboards := guest_embedded_dashboard_filter()) is not None: return query.filter(...)) is untouched and still unconditionally short-circuits before _apply_viewers() is ever reached, for guests and non-guests alike; the test in question exists precisely to prove that early-return, and its intent is unaffected. But it's a genuine, required-check-blocking failure that needs a real fix, not just a rebase artifact to shrug off: the test needs get_user_id() (or g.user) mocked so execution reaches a real query.join() call (or another observable point) before the sentinel is meaningful again — as currently written it will keep failing on every future run regardless of how many more times this PR gets rebased.

Two new bot NITs since round 5 (type-hint suggestions on uuid_ids/int_ids in utils/filters.py and a test-local variable) are trivial style items, not blocking. Bito's suggestion for a dedicated end-to-end guest-flow test in test_get_chart_data.py is a reasonable coverage addition but lower priority than the CI break.

Still not approving — security-boundary PR, escalating to Amin for final sign-off per standing policy — and CI needs to be green before this is mergeable regardless of sign-off.

Comment thread tests/unit_tests/charts/test_filters.py Outdated
filt: ChartFilter = ChartFilter.__new__(ChartFilter)
filt.model = Slice

with pytest.raises(RuntimeError, match="datasource-access join"):

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.

CI is currently failing here: AttributeError: user (flask/ctx.py:54), not the expected RuntimeError sentinel. ChartFilter.apply()'s non-guest tail was refactored upstream to return self._apply_viewers(query), which calls get_user_id() (touching g.user) before anything resembling query.join(...). Since this test never sets up g.user, the AttributeError fires first and the sentinel never gets a chance to prove the guest branch was skipped. Not a security issue (the guest branch above is untouched and still short-circuits first) but this needs a fix — e.g. mocker.patch("superset.charts.filters.get_user_id", return_value=1) — or it will keep failing CI on every future push.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Hey @aminghadersohi CI is passing now

@gabotorresruiz gabotorresruiz force-pushed the feat/mcp-embedded-guest-data-read branch from bc82880 to bc154ac Compare July 8, 2026 20:25
@bito-code-review

bito-code-review Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Code Review Agent Run #985a7e

Actionable Suggestions - 0
Additional Suggestions - 5
  • superset/mcp_service/chart/tool/get_chart_data.py - 1
    • Missing guest-scope tests · Line 38-38
      The diff introduces `guest_scope.is_guest_read()` branching (line 415) and `guest_scope.authorize_query()` (line 629) but `test_get_chart_data.py` has zero tests exercising the guest scope logic. Compare `get_chart_preview.py` lines 1263–1288 which already test both `_authorize_guest_query` paths. Without tests, a future refactor that breaks the guest bypass will go undetected. Per BITO.md [11730], [11731], and [12490], new tools and behavioral logic require dedicated test coverage.
  • superset/utils/filters.py - 1
    • CWE-20: Integer ID Validation Logic · Line 76-77
      Replace the `int_ids` assignment to use `is_int(id_)` instead of `not is_uuid(id_)`. Also add `from superset.models.dashboard import is_int` to the imports.
  • tests/unit_tests/mcp_service/test_privacy.py - 3
    • Inline import should be module-level · Line 42-42
      Move the import of `security_manager` to module-level alongside other imports; inline imports should only be used when preventing circular dependencies (BITO.md rule 12745).
    • Inline import should be module-level · Line 54-54
      Move import to module-level per BITO.md rule 12745 (same issue as line 42).
    • Inline import should be module-level · Line 69-69
      Move import to module-level per BITO.md rule 12745 (same pattern as lines 42, 54).
Filtered by Review Rules

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

  • superset/mcp_service/guest_scope.py - 1
    • CWE-483: Missing exception-path test coverage · Line 69-72
  • tests/unit_tests/mcp_service/chart/tool/test_get_chart_info.py - 1
  • tests/unit_tests/security/manager_test.py - 2
  • superset/mcp_service/mcp_config.py - 1
Review Details
  • Files reviewed - 26 · Commit Range: bc154ac..bc154ac
    • superset/charts/filters.py
    • superset/mcp_service/auth.py
    • superset/mcp_service/chart/tool/get_chart_data.py
    • superset/mcp_service/chart/tool/get_chart_info.py
    • superset/mcp_service/chart/tool/get_chart_preview.py
    • superset/mcp_service/chart/tool/get_chart_sql.py
    • superset/mcp_service/guest_scope.py
    • superset/mcp_service/mcp_config.py
    • superset/mcp_service/privacy.py
    • superset/mcp_service/rls/tool/get_rls_filter_info.py
    • superset/mcp_service/rls/tool/list_rls_filters.py
    • superset/security/manager.py
    • superset/utils/filters.py
    • tests/unit_tests/charts/test_filters.py
    • tests/unit_tests/mcp_service/chart/tool/test_get_chart_data.py
    • tests/unit_tests/mcp_service/chart/tool/test_get_chart_info.py
    • tests/unit_tests/mcp_service/chart/tool/test_get_chart_preview.py
    • tests/unit_tests/mcp_service/chart/tool/test_get_chart_sql.py
    • tests/unit_tests/mcp_service/chart/tool/test_list_charts.py
    • tests/unit_tests/mcp_service/rls/tool/test_rls_tools.py
    • tests/unit_tests/mcp_service/system/tool/test_get_current_user.py
    • tests/unit_tests/mcp_service/test_guest_scope.py
    • tests/unit_tests/mcp_service/test_guest_token_auth.py
    • tests/unit_tests/mcp_service/test_privacy.py
    • tests/unit_tests/security/manager_test.py
    • tests/unit_tests/utils/filters_test.py
  • Files skipped - 2
    • superset/mcp_service/CLAUDE.md - Reason: Filter setting
    • superset/mcp_service/SECURITY.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 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

@aminghadersohi aminghadersohi 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.

Round 7 re-review at HEAD bc154ac71 (rebase/squash of round 6's bc82880c; diff content unchanged). Not approving yet — two housekeeping threads are still open, see below.

All of our own findings across rounds 1–6 are resolved, re-verified at this HEAD (not just re-read):

  • HIGH (dataset tools unscoped for guests) — closed via the default-deny MCP_GUEST_ALLOWED_TOOLS allow-list (auth.py:243, mcp_config.py:161): get_dataset_info/list_datasets/query_dataset are absent from the list and explicitly asserted denied in test_non_allow_listed_tools_denied_to_guest (test_guest_token_auth.py:388, dataset tools listed at 368-370). Intact post-rebase.
  • HIGH (ChartFilter.apply() guest branch untested) — resolved; test_filters.py::test_chart_filter_scopes_guest_to_token_dashboards exercises apply() directly and asserts the compiled SQL clause (EXISTS/IN (1, 2)) rather than mocking around it. Thread marked resolved.
  • MEDIUM (get_chart_sql.py not guest-scoped) — resolved (explicit guest denial).
  • Mixed-uuid/int guest-token bug, PUBLIC_ROLE_LIKE data-model-metadata bypass, non-embedded-dashboard token issuance — all resolved at the root (manager.py:4396 rejects a raw int id whose dashboard isn't .embedded at token-issuance time; utils/filters.py:76-82 ORs uuid/int branches instead of routing everything through one).
  • Our CI-breaking-test inline comment — confirmed fixed: test_chart_filter_non_guest_skips_guest_branch now patches _apply_viewers directly instead of relying on query.join, so it no longer trips over the upstream _apply_viewersget_user_id()g.user refactor. unit-tests-required is green.

Guest-scoping enforcement re-confirmed at this HEAD: ChartFilter.apply() (superset/charts/filters.py:114-120) returns query.filter(self.model.dashboards.any(guest_dashboards)) as an early return — a server-side WHERE, not a fetch-then-drop — so an out-of-scope chart never resolves for a guest via ChartDAO. The MCP-tool allow-list is independent defense-in-depth on top of that (default-deny, fails closed on a misconfigured policy per auth.py's _tool_denied_for_principal). Non-guest path is unaffected (can_access_all_datasources / _apply_viewers unchanged, guest branch short-circuits before it).

Only two things left open, neither security:

  • bito's get_chart_data.py:430 "missing guest scope integration test" — independently verified real: there's no end-to-end test that calls the tool as a guest against an out-of-scope chart and asserts denial (only the ChartFilter.apply() unit test and the tool-allow-list test exist). Worth adding, but not blocking — the primary gate (ChartFilter) and the allow-list are each already directly tested; this would only add belt-and-suspenders coverage. Not re-filing, just corroborating so it isn't lost.
  • codeant's utils/filters.py:77 type-annotation nit — trivial, not security-relevant.

Once those two threads are closed (or explicitly dismissed), this is ready for sign-off from a security standpoint — the guest boundary holds at this HEAD.

@gabotorresruiz gabotorresruiz force-pushed the feat/mcp-embedded-guest-data-read branch from bc154ac to 87fe93f Compare July 9, 2026 16:57
# Embedded guests are scoped to their token's dashboards first. A guest
# is never entitled to all charts, regardless of what its role grants,
# and an empty token scope denies all charts (a deny-all clause).
if (guest_dashboards := guest_embedded_dashboard_filter()) is not None:

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: Replace the inline walrus assignment with a separate local variable declaration and add an explicit type annotation for that variable before the conditional check. [custom_rule]

Severity Level: Minor ⚠️

Why it matters? 🤔

The new walrus assignment introduces a local variable without any type annotation, and this is exactly the kind of newly added Python code the type-hints rule targets. The suggestion correctly identifies a real omission in the added line.

Rule source 📖

.cursor/rules/dev-standard.mdc (line 28)

Fix in Cursor Fix in VSCode Claude

(Use Cmd/Ctrl + Click for best experience)

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

**Path:** superset/charts/filters.py
**Line:** 117:117
**Comment:**
	*Custom Rule: Replace the inline walrus assignment with a separate local variable declaration and add an explicit type annotation for that variable before the conditional check.

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

Comment thread superset/utils/filters.py
# A guest token may mix uuid and int dashboard ids during the uuid rollout.
# Route each id kind to its own column and OR them — a plain int sent to the
# uuid-typed column would raise a bind/type error.
uuid_ids = [id_ for id_ in ids if is_uuid(id_)]

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: Add a concrete type hint for uuid_ids instead of leaving this derived list unannotated. [custom_rule]

Severity Level: Minor ⚠️

Why it matters? 🤔

uuid_ids is a newly introduced derived list and is left unannotated even though its type can be inferred and annotated. This is a real instance of missing type hints in new Python code.

Rule source 📖

.cursor/rules/dev-standard.mdc (line 28)

Fix in Cursor Fix in VSCode Claude

(Use Cmd/Ctrl + Click for best experience)

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

**Path:** superset/utils/filters.py
**Line:** 80:80
**Comment:**
	*Custom Rule: Add a concrete type hint for `uuid_ids` instead of leaving this derived list unannotated.

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

Comment thread superset/utils/filters.py
# Route each id kind to its own column and OR them — a plain int sent to the
# uuid-typed column would raise a bind/type error.
uuid_ids = [id_ for id_ in ids if is_uuid(id_)]
int_ids = [id_ for id_ in ids if not is_uuid(id_)]

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: Add a concrete type hint for int_ids instead of leaving this derived list unannotated. [custom_rule]

Severity Level: Minor ⚠️

Why it matters? 🤔

int_ids is also a new list variable without an explicit type annotation. Since the type is evident, this is a valid type-hint omission under the rule.

Rule source 📖

.cursor/rules/dev-standard.mdc (line 28)

Fix in Cursor Fix in VSCode Claude

(Use Cmd/Ctrl + Click for best experience)

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

**Path:** superset/utils/filters.py
**Line:** 81:81
**Comment:**
	*Custom Rule: Add a concrete type hint for `int_ids` instead of leaving this derived list unannotated.

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

Comment on lines +170 to +172
viewers = mocker.patch.object(
ChartFilter, "_apply_viewers", side_effect=AssertionError("role path")
)

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: Add a concrete type annotation for this local mock object assignment so the new code consistently uses type hints. [custom_rule]

Severity Level: Minor ⚠️

Why it matters? 🤔

This is a real omission of a type hint in newly added Python code: viewers is assigned a mock object and could be annotated, but no explicit type is present.

Rule source 📖

.cursor/rules/dev-standard.mdc (line 28)

Fix in Cursor Fix in VSCode Claude

(Use Cmd/Ctrl + Click for best experience)

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

**Path:** tests/unit_tests/charts/test_filters.py
**Line:** 170:172
**Comment:**
	*Custom Rule: Add a concrete type annotation for this local mock object assignment so the new code consistently uses type hints.

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

assert item["subjects"][0]["label"] == "Alpha"


@pytest.mark.asyncio

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: Add explicit type hints to this async test function signature, including the fixture parameter type and a return type annotation. [custom_rule]

Severity Level: Minor ⚠️

Why it matters? 🤔

The added async test function has no type hints for its fixture argument and no return annotation, which matches the rule requiring type hints on new or modified Python functions where applicable.

Rule source 📖

.cursor/rules/dev-standard.mdc (line 28)

Fix in Cursor Fix in VSCode Claude

(Use Cmd/Ctrl + Click for best experience)

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

**Path:** tests/unit_tests/mcp_service/rls/tool/test_rls_tools.py
**Line:** 249:249
**Comment:**
	*Custom Rule: Add explicit type hints to this async test function signature, including the fixture parameter type and a return type annotation.

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

@gabotorresruiz gabotorresruiz force-pushed the feat/mcp-embedded-guest-data-read branch from 87fe93f to 6548563 Compare July 9, 2026 17:03
@gabotorresruiz gabotorresruiz force-pushed the feat/mcp-embedded-guest-data-read branch from 6548563 to d443dea Compare July 9, 2026 17:20
@gabotorresruiz gabotorresruiz merged commit 1fd43ff into apache:master Jul 9, 2026
59 checks passed
@bito-code-review

Copy link
Copy Markdown
Contributor

Bito Automatic Review Skipped – PR Already Merged

Bito scheduled an automatic review for this pull request, but the review was skipped because this PR was merged before the review could be run.
No action is needed if you didn't intend to review it. To get a review, you can type /review in a comment and save it

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

authentication Related to authentication change:backend Requires changing the backend size/XXL

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants