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


##########
superset/mcp_service/user/schemas.py:
##########
@@ -277,9 +305,17 @@ def serialize_user_object(
     if include_sensitive and include_roles:
         user_roles = getattr(user, "roles", None)
         if user_roles is not None:
-            try:
-                roles = [r.name for r in user_roles if hasattr(r, "name")]
-            except (AttributeError, DetachedInstanceError):
+            roles = []
+            for r in user_roles:
+                try:
+                    if hasattr(r, "name") and isinstance(r.name, str):
+                        roles.append(escape_llm_context_delimiters(r.name))
+                except (AttributeError, DetachedInstanceError):
+                    logger.debug(
+                        "Skipping role that raised exception in 
serialize_user_object"
+                    )
+                    continue
+            if not roles:
                 roles = None

Review Comment:
   **Suggestion:** The new empty-check collapses an explicitly loaded empty 
roles relationship (`[]`) into `None`, which changes semantics from "user has 
no roles" to "roles unavailable/redacted." This breaks callers that rely on 
distinguishing those states and contradicts the added round-trip expectation 
for empty roles. Keep the empty list when roles were loaded and only use `None` 
when roles were not requested or not available. [incorrect condition logic]
   
   <details>
   <summary><b>Severity Level:</b> Major ⚠️</summary>
   
   ```mdx
   - ⚠️ get_user_info tool conflates empty roles and redaction.
   - ⚠️ list_users tool misrepresents users without assigned roles.
   - ⚠️ Unit test for empty-role roundtrip semantics will fail.
   - ⚠️ LLM clients cannot reliably infer user role assignments.
   ```
   </details>
   <details>
   <summary><b>Steps of Reproduction ✅ </b></summary>
   
   ```mdx
   1. Open `superset/tests/unit_tests/mcp_service/user/test_schemas.py` and 
inspect
   `test_serialize_user_object_round_trip_with_empty_roles` at lines 70–82: it 
constructs a
   `user` MagicMock with `user.roles = []` and calls 
`serialize_user_object(user,
   include_sensitive=True, include_roles=True)` imported from
   `superset.mcp_service.user.schemas`.
   
   2. Follow the call into `serialize_user_object` in 
`superset/mcp_service/user/schemas.py`
   at lines 32–61: because `include_sensitive` and `include_roles` are `True`, 
`user_roles =
   getattr(user, "roles", None)` becomes `[]`, the `if user_roles is not None:` 
branch
   executes, `roles` is set to `[]`, the loop over `user_roles` does nothing, 
and then the
   new condition at line 318 `if not roles:` evaluates to `True` and sets 
`roles = None` at
   line 319.
   
   3. Still in `serialize_user_object`, a `UserInfo` instance is created at 
lines 62–77 with
   `roles=roles`, which is now `None`; the `UserInfo` model in the same file at 
lines 94–135
   has `roles: list[str] | None` and a `@field_validator("roles", 
mode="before")` that
   returns `None` unchanged when `v is None`, so the resulting `UserInfo` has 
`info.roles is
   None`, not `[]`.
   
   4. Back in `test_serialize_user_object_round_trip_with_empty_roles` at lines 
82–85, the
   test asserts `info.roles == []`, expecting an explicitly empty list to be 
preserved; with
   the current implementation this assertion fails (or, in a running MCP 
deployment, any
   client observing the tool output from `get_user_info` in
   `superset/mcp_service/user/tool/get_user_info.py` or `list_users` in
   `superset/mcp_service/user/tool/list_users.py` will see `roles` as `null` 
instead of `[]`
   for users whose `roles` relationship is an explicitly loaded empty list, 
making it
   impossible to distinguish "no roles" from "roles redacted/not loaded").
   ```
   </details>
   
   [Fix in 
Cursor](https://app.codeant.ai/fix-in-ide?tool=cursor&prompt_id=cb3e891097b448db82d4d0ffb157ba1a&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
 | [Fix in VSCode 
Claude](https://app.codeant.ai/fix-in-ide?tool=vscode-claude&prompt_id=cb3e891097b448db82d4d0ffb157ba1a&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/user/schemas.py
   **Line:** 318:319
   **Comment:**
        *Incorrect Condition Logic: The new empty-check collapses an explicitly 
loaded empty roles relationship (`[]`) into `None`, which changes semantics 
from "user has no roles" to "roles unavailable/redacted." This breaks callers 
that rely on distinguishing those states and contradicts the added round-trip 
expectation for empty roles. Keep the empty list when roles were loaded and 
only use `None` when roles were not requested or not available.
   
   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%2F40746&comment_hash=bc69a4a3c9491bbc6c23029a881078005de046f0fc3e0923a62c0d781af999c5&reaction=like'>👍</a>
 | <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F40746&comment_hash=bc69a4a3c9491bbc6c23029a881078005de046f0fc3e0923a62c0d781af999c5&reaction=dislike'>👎</a>



##########
superset/mcp_service/user/schemas.py:
##########
@@ -277,9 +305,17 @@ def serialize_user_object(
     if include_sensitive and include_roles:
         user_roles = getattr(user, "roles", None)
         if user_roles is not None:
-            try:
-                roles = [r.name for r in user_roles if hasattr(r, "name")]
-            except (AttributeError, DetachedInstanceError):
+            roles = []
+            for r in user_roles:
+                try:
+                    if hasattr(r, "name") and isinstance(r.name, str):
+                        roles.append(escape_llm_context_delimiters(r.name))
+                except (AttributeError, DetachedInstanceError):
+                    logger.debug(
+                        "Skipping role that raised exception in 
serialize_user_object"
+                    )
+                    continue
+            if not roles:
                 roles = None

Review Comment:
   **🟠 Architect Review — HIGH**
   
   The serializer collapses an explicitly loaded-but-empty user.roles 
relationship to None, making "user has no roles" indistinguishable from "roles 
were not included/redacted." This contradicts the new tests (which assert 
UserInfo.roles == [] for empty roles) and changes the pre-PR behavior where 
empty roles were serialized as [].
   
   **Suggestion:** Stop collapsing an empty roles list to None: when user.roles 
is present but empty (or all entries are skipped), keep roles as [], and 
reserve None only for cases where roles are intentionally omitted 
(include_sensitive=False or include_roles=False); keep the tests enforcing this 
contract.
   
   
   [Fix in 
Cursor](https://app.codeant.ai/fix-in-ide?tool=cursor&prompt_id=214ace98861845f69308515bf4f9ebaf&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
 | [Fix in VSCode 
Claude](https://app.codeant.ai/fix-in-ide?tool=vscode-claude&prompt_id=214ace98861845f69308515bf4f9ebaf&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 an **Architect / Logical Review** comment left during a code review. 
These reviews are first-class, important findings — not optional suggestions. 
Do NOT dismiss this as a 'big architectural change' just because the title says 
architect review; most of these can be resolved with a small, localized fix 
once the intent is understood.
   
   **Path:** superset/mcp_service/user/schemas.py
   **Line:** 308:319
   **Comment:**
        *HIGH: The serializer collapses an explicitly loaded-but-empty 
user.roles relationship to None, making "user has no roles" indistinguishable 
from "roles were not included/redacted." This contradicts the new tests (which 
assert UserInfo.roles == [] for empty roles) and changes the pre-PR behavior 
where empty roles were serialized as [].
   
   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.
   If a suggested approach is provided above, use it as the authoritative 
instruction. If no explicit code suggestion is given, you MUST still draft and 
apply your own minimal, localized fix — do not punt back with 'no suggestion 
provided, review manually'. Keep the change as small as possible: add a guard 
clause, gate on a loading state, reorder an await, wrap in a conditional, etc. 
Do not refactor surrounding code or expand scope beyond the finding.
   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>



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