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


##########
superset/extensions/api.py:
##########
@@ -102,18 +146,68 @@ def get_list(self, **kwargs: Any) -> Response:
             500:
               $ref: '#/components/responses/500'
         """
-        result = []
         extensions = get_extensions()
-        for extension in extensions.values():
-            extension_data = build_extension_data(extension)
-            result.append(extension_data)
+        ext_list = list(extensions.values())
+
+        q_args: dict[str, Any] = {}
+        if q_str := request.args.get("q"):
+            try:
+                q_args = rison.loads(q_str)
+            except Exception:
+                return self.response_400(message="Invalid rison query 
parameter")
+
+            if not isinstance(q_args, dict):
+                return self.response_400(
+                    message="Query parameter must be a rison object"
+                )
+
+            ext_list, error = self._apply_q(ext_list, q_args)
+            if error:
+                return self.response_400(message=error)
+
+        total_count = len(ext_list)
+
+        page = q_args.get("page")
+        page_size = q_args.get("page_size", DEFAULT_PAGE_SIZE)
+        if page is not None:
+            start = page * page_size
+            ext_list = ext_list[start : start + page_size]
+
+        result = [build_extension_data(ext) for ext in ext_list]
+        return self.response(200, result=result, count=total_count)
+
+    @staticmethod
+    def _apply_q(
+        ext_list: list[LoadedExtension], q_args: dict[str, Any]
+    ) -> tuple[list[LoadedExtension], str | None]:
+        """Apply filters and search from a parsed q parameter."""
+        if filters := q_args.get("filters"):
+            if not isinstance(filters, list):
+                return ext_list, "'filters' must be a list"
+            for f in filters:
+                col = f.get("col")
+                value = f.get("value")

Review Comment:
   **Suggestion:** The filter loop assumes every entry in `filters` is a dict 
and immediately calls `.get(...)`; a malformed payload like `filters=[1]` will 
raise `AttributeError` and return 500 instead of a client error. Validate each 
filter item is a dict before accessing keys and return a 400 for invalid 
shapes. [type error]
   
   <details>
   <summary><b>Severity Level:</b> Major ⚠️</summary>
   
   ```mdx
   - ❌ Extensions listing endpoint 500s on malformed `filters` payload.
   - ⚠️ Bad clients can crash endpoint instead of 400 response.
   ```
   </details>
   <details>
   <summary><b>Steps of Reproduction ✅ </b></summary>
   
   ```mdx
   1. Start a Superset instance running the PR code so that the 
`ExtensionsRestApi` class in
   `superset/extensions/api.py:57` is registered by Flask-AppBuilder.
   
   2. Issue an HTTP GET request to the list endpoint handled by 
`ExtensionsRestApi.get_list`
   (`superset/extensions/api.py:96-177`), with a `q` query parameter containing 
a Rison
   object where `filters` is a list containing a non-dict element, e.g. 
`q=(filters:!(1))`.
   
   3. In `get_list`, the code at `superset/extensions/api.py:152-156` calls
   `rison.loads(q_str)` which successfully parses the Rison string into `q_args 
= {"filters":
   [1]}`, then calls `self._apply_q(ext_list, q_args)` at line 164.
   
   4. Inside `_apply_q` (`superset/extensions/api.py:179-210`), `filters` is a 
list so it
   passes the `isinstance(filters, list)` check at line 185, then the loop `for 
f in
   filters:` at line 187 iterates with `f == 1` and immediately executes 
`f.get("col")` at
   line 188, raising `AttributeError: 'int' object has no attribute 'get'` and 
causing a 500
   Internal Server Error instead of returning a 400 client error.
   ```
   </details>
   
   [Fix in 
Cursor](https://app.codeant.ai/fix-in-ide?tool=cursor&prompt_id=3988f4c58ab94d67a4a129630662e241&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=3988f4c58ab94d67a4a129630662e241&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/extensions/api.py
   **Line:** 187:189
   **Comment:**
        *Type Error: The filter loop assumes every entry in `filters` is a dict 
and immediately calls `.get(...)`; a malformed payload like `filters=[1]` will 
raise `AttributeError` and return 500 instead of a client error. Validate each 
filter item is a dict before accessing keys and return a 400 for invalid shapes.
   
   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%2F40823&comment_hash=3e2dff0af42b1df34c907eac8696d357b641a1cc246083859d7e90af4f9652d0&reaction=like'>👍</a>
 | <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F40823&comment_hash=3e2dff0af42b1df34c907eac8696d357b641a1cc246083859d7e90af4f9652d0&reaction=dislike'>👎</a>



##########
superset/extensions/api.py:
##########
@@ -102,18 +146,68 @@ def get_list(self, **kwargs: Any) -> Response:
             500:
               $ref: '#/components/responses/500'
         """
-        result = []
         extensions = get_extensions()
-        for extension in extensions.values():
-            extension_data = build_extension_data(extension)
-            result.append(extension_data)
+        ext_list = list(extensions.values())
+
+        q_args: dict[str, Any] = {}
+        if q_str := request.args.get("q"):
+            try:
+                q_args = rison.loads(q_str)
+            except Exception:
+                return self.response_400(message="Invalid rison query 
parameter")
+
+            if not isinstance(q_args, dict):
+                return self.response_400(
+                    message="Query parameter must be a rison object"
+                )
+
+            ext_list, error = self._apply_q(ext_list, q_args)
+            if error:
+                return self.response_400(message=error)
+
+        total_count = len(ext_list)
+
+        page = q_args.get("page")
+        page_size = q_args.get("page_size", DEFAULT_PAGE_SIZE)
+        if page is not None:
+            start = page * page_size
+            ext_list = ext_list[start : start + page_size]

Review Comment:
   **Suggestion:** Pagination parameters from `q` are used without type 
validation, so non-integer values (for example `page: "1"` or `page_size: 
"10"`) will make `start` and slicing fail with `TypeError`, producing a 500 
response. Enforce integer pagination values and reject invalid types with 400. 
[type error]
   
   <details>
   <summary><b>Severity Level:</b> Major ⚠️</summary>
   
   ```mdx
   - ❌ Extensions listing endpoint 500s when `page` not integer.
   - ⚠️ Pagination misbehaviour prevents clients gracefully handling invalid 
inputs.
   ```
   </details>
   <details>
   <summary><b>Steps of Reproduction ✅ </b></summary>
   
   ```mdx
   1. Run Superset with the PR code so that `ExtensionsRestApi.get_list` in
   `superset/extensions/api.py:96-177` is exposed through Flask-AppBuilder.
   
   2. Send an HTTP GET request to the list endpoint handled by `get_list`, 
providing a `q`
   query parameter where `page` (or `page_size`) is a non-integer Rison value, 
e.g.
   `q=(page:'1')` which `rison.loads` parses as `{"page": "1"}`.
   
   3. In `get_list`, after `_apply_q` returns, the code at
   `superset/extensions/api.py:170-171` assigns `page = "1"` and `page_size = 
100` (default),
   then computes `start = page * page_size` at line 173, which yields the 
string `"1"`
   repeated 100 times because `"1" * 100` is valid Python.
   
   4. The next line `ext_list = ext_list[start : start + page_size]` at
   `superset/extensions/api.py:174` attempts to evaluate `start + page_size` 
where `start` is
   a long string and `page_size` is an `int`, raising `TypeError` and resulting 
in a 500
   Internal Server Error instead of a 400 response indicating invalid 
pagination parameters.
   ```
   </details>
   
   [Fix in 
Cursor](https://app.codeant.ai/fix-in-ide?tool=cursor&prompt_id=fe044a2077474fddb9418861711fc2fd&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=fe044a2077474fddb9418861711fc2fd&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/extensions/api.py
   **Line:** 170:174
   **Comment:**
        *Type Error: Pagination parameters from `q` are used without type 
validation, so non-integer values (for example `page: "1"` or `page_size: 
"10"`) will make `start` and slicing fail with `TypeError`, producing a 500 
response. Enforce integer pagination values and reject invalid types with 400.
   
   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%2F40823&comment_hash=e87a9f9f6d7630b9462d1bfb93e67d2b8ba97a147726464be06ccf7e40031a62&reaction=like'>👍</a>
 | <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F40823&comment_hash=e87a9f9f6d7630b9462d1bfb93e67d2b8ba97a147726464be06ccf7e40031a62&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