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


##########
superset/mcp_service/dashboard/tool/update_dashboard.py:
##########
@@ -203,6 +227,15 @@ def _apply_field_updates(dashboard: Any, request: 
UpdateDashboardRequest) -> lis
         update_tags(ObjectType.dashboard, dashboard.id, dashboard.tags, 
request.tags)
         changed.append("tags")
 
+    if request.owners is not None:
+        # Full replacement of owners (empty list clears them). IDs are
+        # validated up front in _validate_update_request, so resolving here
+        # only maps the already-verified IDs to user objects.
+        owner_users: list[Any]
+        owner_users, _missing = _resolve_owners(request.owners)
+        dashboard.owners = owner_users
+        changed.append("owners")
+

Review Comment:
   **Suggestion:** The owner IDs are resolved a second time during mutation, 
but unresolved IDs are ignored in this phase. If a user is deleted between 
validation and apply, the update will still commit with a silently truncated 
owner list instead of returning `OwnersNotFound`, violating the 
full-replacement contract. Reuse the validated resolved users from the 
validation step (or re-check `_missing` and fail) so owner replacement is 
atomic and deterministic. [race condition]
   
   <details>
   <summary><b>Severity Level:</b> Major ⚠️</summary>
   
   ```mdx
   ⚠️ MCP update_dashboard owner replacement can be nondeterministic.
   ⚠️ Concurrent user deletion silently truncates requested owner list.
   ⚠️ Full-replacement owners semantics violated under concurrent changes.
   ```
   </details>
   <details>
   <summary><b>Steps of Reproduction ✅ </b></summary>
   
   ```mdx
   1. Start Superset with the MCP service and ensure the `update_dashboard` 
tool is
   available; the tool entrypoint is defined in
   `superset/mcp_service/dashboard/tool/update_dashboard.py:333-418` in the
   `update_dashboard(request: UpdateDashboardRequest, ctx: Context)` function.
   
   2. Trigger an update via MCP as in
   
`tests/unit_tests/mcp_service/dashboard/tool/test_update_dashboard.py:144-162`, 
calling
   the tool with a non-empty owners list, for example `{"identifier": 42, 
"owners": [5, 9]}`
   so that both user IDs initially exist and resolve in 
`security_manager.get_user_by_id`.
   
   3. During the same tool call, the handler in `update_dashboard` first runs
   `_validate_update_request(dashboard, request)` at
   `superset/mcp_service/dashboard/tool/update_dashboard.py:123-201`, which 
calls
   `_resolve_owners(request.owners)` at lines 177-185; both IDs (5 and 9) 
resolve,
   `missing_owner_ids` is empty, and validation succeeds, allowing the request 
to proceed.
   
   4. Before `_apply_field_updates(dashboard, request)` is executed (invoked in 
the
   `update_dashboard` body at
   `superset/mcp_service/dashboard/tool/update_dashboard.py:382-387`), another 
process
   deletes user ID 9 so that `security_manager.get_user_by_id(9)` now returns 
`None`; when
   `_apply_field_updates` reaches the owners branch at lines 230-238, it calls
   `_resolve_owners(request.owners)` a second time, receives `users=[user5]` and
   `missing=[9]`, but ignores `_missing` and sets `dashboard.owners = 
owner_users` followed
   by `db.session.commit()` at lines 58-58, silently dropping the requested 
owner 9 without
   returning an `OwnersNotFound` error despite the full-replacement contract.
   ```
   </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=a18c91fd5d1740739edee98db35b6bd6&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=a18c91fd5d1740739edee98db35b6bd6&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/mcp_service/dashboard/tool/update_dashboard.py
   **Line:** 235:238
   **Comment:**
        *Race Condition: The owner IDs are resolved a second time during 
mutation, but unresolved IDs are ignored in this phase. If a user is deleted 
between validation and apply, the update will still commit with a silently 
truncated owner list instead of returning `OwnersNotFound`, violating the 
full-replacement contract. Reuse the validated resolved users from the 
validation step (or re-check `_missing` and fail) so owner replacement is 
atomic and deterministic.
   
   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%2F42002&comment_hash=11e2b7ebaedd411a7a168aaec8e8d0b57e469a27688a697d0a67456ebb3ff578&reaction=like'>👍</a>
 | <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F42002&comment_hash=11e2b7ebaedd411a7a168aaec8e8d0b57e469a27688a697d0a67456ebb3ff578&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