codeant-ai-for-open-source[bot] commented on code in PR #38576:
URL: https://github.com/apache/superset/pull/38576#discussion_r3482109723


##########
superset/tasks/thumbnails.py:
##########
@@ -90,6 +93,9 @@ def cache_dashboard_thumbnail(
     dashboard = Dashboard.get(dashboard_id)
     url = get_url_path("Superset.dashboard", dashboard_id_or_slug=dashboard.id)
 
+    screenshot = DashboardScreenshot(url, dashboard.digest)
+    resolved_cache_key = cache_key or screenshot.get_cache_key(window_size, 
thumb_size)

Review Comment:
   **Suggestion:** `DashboardScreenshot` is instantiated before 
`override_user(user)`, so `dashboard.digest` is computed without the executor 
user context. For `THUMBNAIL_EXECUTORS = [CURRENT_USER]` this can resolve to 
`None` in Celery, and the fallback `resolved_cache_key` is then derived from a 
non-user-aware digest, causing incorrect cache keys (including possible 
cross-dashboard collisions) when callers don't pass `cache_key` (for example 
`Dashboard.update_thumbnail(force=True)`). Move screenshot/digest-derived 
cache-key resolution inside the `override_user(user)` block (or compute digest 
using the selected executor explicitly) so the key is generated under the same 
user context used for rendering. [cache]
   
   <details>
   <summary><b>Severity Level:</b> Major ⚠️</summary>
   
   ```mdx
   - ❌ SQLA dashboard thumbnail listeners write thumbnails under shared cache 
key.
   - ⚠️ Dashboard update_thumbnail caches unused by thumbnail API.
   ```
   </details>
   <details>
   <summary><b>Steps of Reproduction ✅ </b></summary>
   
   ```mdx
   1. Enable thumbnail listeners so dashboard saves trigger background 
thumbnails: in
   `superset/models/dashboard.py:471-474` the `update_thumbnail` SQLA listener 
is registered
   when `THUMBNAILS_SQLA_LISTENERS` is enabled, and 
`Dashboard.update_thumbnail()` at
   `superset/models/dashboard.py:352-357` calls
   `cache_dashboard_thumbnail.delay(current_user=get_current_user(), 
dashboard_id=self.id,
   force=True)` with no `cache_key`.
   
   2. A Celery worker picks up the task and executes 
`cache_dashboard_thumbnail` in
   `superset/tasks/thumbnails.py:77-85`; inside it, the dashboard is loaded
   (`Dashboard.get(dashboard_id)`) and `screenshot = DashboardScreenshot(url,
   dashboard.digest)` is instantiated at `superset/tasks/thumbnails.py:93-96` 
before any
   `override_user(user)` is applied, so Flask `g.user` is still unset in the 
worker.
   
   3. Accessing `dashboard.digest` in that call invokes the `digest` property in
   `superset/models/dashboard.py:229-231`, which delegates to 
`get_dashboard_digest` in
   `superset/thumbnails/digest.py:80-43`; there `get_executor` is called with
   `current_user=get_current_user()` (`superset/tasks/utils.py:53-58`), but in 
the Celery
   context `get_current_user()` returns `None`, `THUMBNAIL_EXECUTORS` is
   `[ExecutorType.CURRENT_USER]` (`superset/config.py:1108`), so `get_executor` 
fails to find
   an executor and `ExecutorNotFoundError` is caught, causing 
`get_dashboard_digest` to
   return `None` and thus `dashboard.digest` is `None` in the worker.
   
   4. Back in `cache_dashboard_thumbnail`, `resolved_cache_key = cache_key or
   screenshot.get_cache_key(window_size, thumb_size)` at 
`superset/tasks/thumbnails.py:96-98`
   now computes a fallback cache key because `cache_key` was not provided by
   `Dashboard.update_thumbnail`; `DashboardScreenshot.get_cache_key`
   (`superset/utils/screenshots.py:399-31`) hashes only `thumbnail_type`, 
`digest` (now
   `None`), `window_size`, `thumb_size`, and `permalink_key`—it does not include
   `dashboard_id`—so multiple dashboards updated via the SQLA listener share 
the same
   fallback cache key in Celery, leading to cross-dashboard cache collisions 
and cache
   entries that do not match the user-specific digest-based keys generated in
   `DashboardRestApi.thumbnail` (`superset/dashboards/api.py:2-21`), where
   `DashboardScreenshot(dashboard_url, dashboard.digest)` is instantiated under 
the correct
   `current_user` context and `cache_key` is passed explicitly to the task.
   ```
   </details>
   
   [![Fix in 
Cursor](https://new-codeant-butcket.s3.us-west-1.amazonaws.com/badges/fix-in-cursor-flat.svg)](https://app.codeant.ai/fix-in-ide?tool=cursor&prompt_id=77c60348f531449ca0186dac335fb065&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
 [![Fix in VSCode 
Claude](https://new-codeant-butcket.s3.us-west-1.amazonaws.com/badges/fix-in-vscode-claude-flat.svg)](https://app.codeant.ai/fix-in-ide?tool=vscode-claude&prompt_id=77c60348f531449ca0186dac335fb065&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
   
   *(Use Cmd/Ctrl + Click for best experience)*
   <details>
   <summary><b>Prompt for AI Agent 🤖 </b></summary>
   
   ```mdx
   This is a comment left during a code review.
   
   **Path:** superset/tasks/thumbnails.py
   **Line:** 96:97
   **Comment:**
        *Cache: `DashboardScreenshot` is instantiated before 
`override_user(user)`, so `dashboard.digest` is computed without the executor 
user context. For `THUMBNAIL_EXECUTORS = [CURRENT_USER]` this can resolve to 
`None` in Celery, and the fallback `resolved_cache_key` is then derived from a 
non-user-aware digest, causing incorrect cache keys (including possible 
cross-dashboard collisions) when callers don't pass `cache_key` (for example 
`Dashboard.update_thumbnail(force=True)`). Move screenshot/digest-derived 
cache-key resolution inside the `override_user(user)` block (or compute digest 
using the selected executor explicitly) so the key is generated under the same 
user context used for rendering.
   
   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
   ```
   </details>
   <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F38576&comment_hash=cc7787dd46d973d6f766389eca3a335ba5c222c866b05eaca64435e7c02a25d9&reaction=like'>👍</a>
 | <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F38576&comment_hash=cc7787dd46d973d6f766389eca3a335ba5c222c866b05eaca64435e7c02a25d9&reaction=dislike'>👎</a>



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to