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


##########
superset-frontend/src/features/alerts/components/NotificationMethod.tsx:
##########
@@ -355,83 +310,134 @@ export const NotificationMethod: 
FunctionComponent<NotificationMethodProps> = ({
     }
   };
 
-  const fetchSlackChannels = async ({
+  const fetchSlackChannels = ({
     searchString = '',
     types = [],
     exactMatch = false,
     force = false,
+    page,
+    pageSize,
   }: {
-    searchString?: string | undefined;
+    searchString?: string;
     types?: string[];
-    exactMatch?: boolean | undefined;
-    force?: boolean | undefined;
+    exactMatch?: boolean;
+    force?: boolean;
+    page?: number;
+    pageSize?: number;
   } = {}): Promise<JsonResponse> => {
     const queryString = rison.encode({
-      searchString,
+      search_string: searchString,
       types,
-      exactMatch,
+      exact_match: exactMatch,
       force,
+      ...(page !== undefined ? { page } : {}),
+      ...(pageSize !== undefined ? { page_size: pageSize } : {}),
     });
     const endpoint = `/api/v1/report/slack_channels/?q=${queryString}`;
     return SupersetClient.get({ endpoint });

Review Comment:
   **Suggestion:** `searchString` is inserted into the URL using 
`rison.encode`, not URL-safe encoding. Inputs containing characters like `#`, 
`&`, or `?` can break/truncate the `q` query parameter before it reaches the 
API, so server-side search behaves incorrectly. Use URI-safe Rison encoding for 
query params (as done in other fetchers) before interpolating into the 
endpoint. [api mismatch]
   
   <details>
   <summary><b>Severity Level:</b> Major ⚠️</summary>
   
   ```mdx
   - ⚠️ SlackV2 channel search misbehaves for reserved characters.
   - ⚠️ Large-workspace Slack recipient search becomes unreliable.
   - ⚠️ Inconsistent Rison usage versus email recipient fetcher.
   ```
   </details>
   <details>
   <summary><b>Steps of Reproduction ✅ </b></summary>
   
   ```mdx
   1. Open the Alerts and Reports modal and add a Slack notification method so 
that
   NotificationMethod renders, as wired in AlertReportModal.tsx lines 2688-2727 
where
   <NotificationMethod /> is mapped over notificationSettings.
   
   2. In NotificationMethod.tsx lines 253-267 and 679-12, select SlackV2 as the 
delivery
   method so the SlackV2 AsyncSelect is rendered and begin typing a search 
string containing
   URL-reserved characters such as `?`, `#`, or `&` in the recipients picker 
(this value is
   passed as the `search` argument into loadSlackChannels at lines 123-145).
   
   3. Observe that loadSlackChannels at NotificationMethod.tsx lines 123-145 
delegates to
   fetchSlackChannels at lines 94-119, which builds `queryString` using 
`rison.encode` at
   line 109 with the raw `searchString` and interpolates it directly into the 
endpoint
   `/api/v1/report/slack_channels/?q=${queryString}` at line 117.
   
   4. Because `rison.encode` does not URI-escape reserved characters and the 
resulting string
   is used verbatim in the query parameter, the browser issues a GET where the 
`q` parameter
   is truncated or split at the reserved characters, so the backend receives a 
corrupted
   Rison payload; server-side filtering for Slack channel search can misbehave 
or fail for
   such inputs, unlike fetchEmailRecipientOptions at lines 217-247 which uses
   `rison.encode_uri` specifically to avoid this issue.
   ```
   </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=c52f6e8ec49f4909bd68652da15ffddb&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=c52f6e8ec49f4909bd68652da15ffddb&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-frontend/src/features/alerts/components/NotificationMethod.tsx
   **Line:** 328:337
   **Comment:**
        *Api Mismatch: `searchString` is inserted into the URL using 
`rison.encode`, not URL-safe encoding. Inputs containing characters like `#`, 
`&`, or `?` can break/truncate the `q` query parameter before it reaches the 
API, so server-side search behaves incorrectly. Use URI-safe Rison encoding for 
query params (as done in other fetchers) before interpolating into the endpoint.
   
   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%2F41998&comment_hash=57c9480035bb0db01e032faaec38d0541591a24b72d9b0a699af80dd576c5843&reaction=like'>👍</a>
 | <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F41998&comment_hash=57c9480035bb0db01e032faaec38d0541591a24b72d9b0a699af80dd576c5843&reaction=dislike'>👎</a>



##########
superset-frontend/src/features/alerts/components/NotificationMethod.tsx:
##########
@@ -665,23 +671,26 @@ export const NotificationMethod: 
FunctionComponent<NotificationMethodProps> = ({
                   ) : (
                     // for SlackV2
                     <div className="input-container">
-                      <Select
+                      <AsyncSelect
+                        key={slackRefreshKey}
                         ariaLabel={t('Select channels')}
                         mode="multiple"
                         name="recipients"
                         value={slackRecipients}
-                        options={slackOptions}
+                        options={loadSlackChannels}
                         onChange={onSlackRecipientsChange}
+                        onError={() => setUseSlackV1(true)}
                         allowClear

Review Comment:
   **Suggestion:** Setting `useSlackV1` in `onError` does not actually switch 
the active picker when the current method is SlackV2, so fetch failures can 
leave users stuck in the failing AsyncSelect path instead of falling back 
automatically. Ensure the fallback also updates the selected notification 
method (or render branch) so the UI truly moves to Slack V1 input on error. 
[incomplete implementation]
   
   <details>
   <summary><b>Severity Level:</b> Major ⚠️</summary>
   
   ```mdx
   - ⚠️ SlackV2 picker does not auto-fallback on errors.
   - ⚠️ Users stay on a broken SlackV2 input path.
   - ⚠️ Manual reconfiguration required to reach Slack V1.
   ```
   </details>
   <details>
   <summary><b>Steps of Reproduction ✅ </b></summary>
   
   ```mdx
   1. Ensure the SlackV2 feature flag is enabled so SlackV2 can be selected;
   AlertReportModal.tsx lines 214-215 read allowedNotificationMethods, and
   NotificationMethod.tsx lines 42-65 use 
`isFeatureEnabled(FeatureFlag.AlertReportSlackV2)`
   to include SlackV2 in methodOptions when `useSlackV1` is false.
   
   2. Open the Alerts or Reports modal and configure a notification whose 
NotificationSetting
   has `method: NotificationMethodOption.SlackV2`, as exemplified by 
mockSettingSlackV2 in
   NotificationMethod.test.tsx lines 225-233; this causes NotificationMethod to 
render the
   SlackV2 AsyncSelect branch at lines 253-267 and 679-12.
   
   3. Induce a failure in the SlackV2 channel fetch (for example by having 
SupersetClient.get
   reject inside loadSlackChannels at NotificationMethod.tsx lines 123-145) so 
that the
   AsyncSelect options loader throws; the AsyncSelect invokes its `onError` 
handler defined
   at line 683 as `() => setUseSlackV1(true)`, which flips `useSlackV1` to true 
but leaves
   `setting.method` as `NotificationMethodOption.SlackV2`.
   
   4. After `useSlackV1` is true, methodOptions at NotificationMethod.tsx lines 
42-65 filter
   out SlackV2 and only include Slack, yet the current `method` prop still 
equals `SlackV2`;
   the Select’s `value` is computed as `methodOptions.find(option => 
option.value ===
   method)` at lines 143-156 and becomes undefined, and the recipients branch 
at lines
   204-253 continues to render the SlackV2 AsyncSelect because it switches 
solely on
   `method`, not `useSlackV1`, leaving the user on the failing SlackV2 picker 
instead of
   automatically transitioning to the working SlackV1 textarea.
   ```
   </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=a4689e0ebfb0496098284ba6d488f558&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=a4689e0ebfb0496098284ba6d488f558&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-frontend/src/features/alerts/components/NotificationMethod.tsx
   **Line:** 683:683
   **Comment:**
        *Incomplete Implementation: Setting `useSlackV1` in `onError` does not 
actually switch the active picker when the current method is SlackV2, so fetch 
failures can leave users stuck in the failing AsyncSelect path instead of 
falling back automatically. Ensure the fallback also updates the selected 
notification method (or render branch) so the UI truly moves to Slack V1 input 
on error.
   
   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%2F41998&comment_hash=3934f32d70fed3b2d3d9171e4180eea9265639392fde73aab0f2f6e6942d38ea&reaction=like'>👍</a>
 | <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F41998&comment_hash=3934f32d70fed3b2d3d9171e4180eea9265639392fde73aab0f2f6e6942d38ea&reaction=dislike'>👎</a>



##########
superset-frontend/src/features/alerts/components/NotificationMethod.tsx:
##########
@@ -355,83 +310,134 @@ export const NotificationMethod: 
FunctionComponent<NotificationMethodProps> = ({
     }
   };
 
-  const fetchSlackChannels = async ({
+  const fetchSlackChannels = ({
     searchString = '',
     types = [],
     exactMatch = false,
     force = false,
+    page,
+    pageSize,
   }: {
-    searchString?: string | undefined;
+    searchString?: string;
     types?: string[];
-    exactMatch?: boolean | undefined;
-    force?: boolean | undefined;
+    exactMatch?: boolean;
+    force?: boolean;
+    page?: number;
+    pageSize?: number;
   } = {}): Promise<JsonResponse> => {
     const queryString = rison.encode({
-      searchString,
+      search_string: searchString,
       types,
-      exactMatch,
+      exact_match: exactMatch,
       force,
+      ...(page !== undefined ? { page } : {}),
+      ...(pageSize !== undefined ? { page_size: pageSize } : {}),
     });
     const endpoint = `/api/v1/report/slack_channels/?q=${queryString}`;
     return SupersetClient.get({ endpoint });
   };
 
-  const updateSlackOptions = async ({
-    force,
-  }: {
-    force?: boolean | undefined;
-  } = {}) => {
-    setIsSlackChannelsLoading(true);
-    fetchSlackChannels({ types: ['public_channel', 'private_channel'], force })
-      .then(({ json }) => {
-        const { result } = json;
-        const options: SlackOptionsType = mapChannelsToOptions(result);
-
-        setSlackOptions(options);
-
-        if (isFeatureEnabled(FeatureFlag.AlertReportSlackV2)) {
-          // for edit mode, map existing ids to names for display if slack v2
-          // or names to ids if slack v1
-          const [publicOptions, privateOptions] = options;
-          if (
-            method &&
-            [
-              NotificationMethodOption.SlackV2,
-              NotificationMethodOption.Slack,
-            ].includes(method)
-          ) {
-            setSlackRecipients(
-              mapSlackValues({
-                method,
-                recipientValue,
-                slackOptions: [
-                  ...publicOptions.options,
-                  ...privateOptions.options,
-                ],
-              }),
-            );
-          }
-        }
-      })
-      .catch(() => {
-        // Fallback to slack v1 if slack v2 is not compatible
-        setUseSlackV1(true);
-      })
-      .finally(() => {
-        setMethodOptionsLoading(false);
-        setIsSlackChannelsLoading(false);
+  // Lazily fetch one page of channels as the user searches, so workspaces with
+  // tens of thousands of channels never load the whole list into the browser.
+  const loadSlackChannels = useCallback(
+    async (search: string, page: number, pageSize: number) => {
+      const force = forceRefreshSlackRef.current;
+      forceRefreshSlackRef.current = false;
+      const { json } = await fetchSlackChannels({
+        searchString: search,
+        types: ['public_channel', 'private_channel'],
+        force,
+        page,
+        pageSize,
       });
+      const result = (json?.result ?? []) as SlackChannel[];
+      return {
+        data: result.map(channel => ({
+          label:
+            !channel.is_private && !channel.is_member
+              ? `${channel.name} ${t('(Bot not in channel)')}`
+              : channel.name,
+          value: channel.id,
+        })),
+        totalCount: json?.count ?? result.length,
+      };
+    },
+    // fetchSlackChannels only closes over stable refs/imports
+    // eslint-disable-next-line react-hooks/exhaustive-deps
+    [],
+  );
+
+  const onRefreshSlackChannels = () => {
+    forceRefreshSlackRef.current = true;
+    // Remount the AsyncSelect so its internal result cache is discarded and 
the
+    // forced (cache-busting) fetch runs.
+    setSlackRefreshKey(key => key + 1);
   };
 
+  // Resolve the channel ids saved on an existing SlackV2 report into
+  // human-readable labels. Bounded by exact_match so it never enumerates the
+  // whole workspace.
   useEffect(() => {
+    let cancelled = false;
     const slackEnabled = options?.some(
       option =>
         option === NotificationMethodOption.Slack ||
         option === NotificationMethodOption.SlackV2,
     );
-    if (slackEnabled && !slackOptions[0]?.options.length) {
-      updateSlackOptions();
+    const savedIds =
+      method === NotificationMethodOption.SlackV2 && recipientValue
+        ? recipientValue
+            .split(',')
+            .map(value => value.trim())
+            .filter(Boolean)
+        : [];
+
+    const resolveSavedRecipients = async () => {
+      // Show the saved ids immediately so the existing selection is always
+      // visible, then enrich with channel names once the lookup resolves.
+      if (savedIds.length && !cancelled) {
+        setSlackRecipients(savedIds.map(id => ({ label: id, value: id })));
+      }
+      try {
+        if (savedIds.length) {
+          const { json } = await fetchSlackChannels({
+            searchString: recipientValue,
+            types: ['public_channel', 'private_channel'],
+            exactMatch: true,
+          });
+          const result = (json?.result ?? []) as SlackChannel[];
+          const namesById = new Map(
+            result.map(channel => [channel.id, channel.name]),
+          );
+          if (!cancelled) {
+            setSlackRecipients(
+              savedIds.map(id => ({
+                label: namesById.get(id) ?? id,
+                value: id,
+              })),
+            );
+          }
+        }
+      } catch {
+        // Keep the raw ids as labels; the AsyncSelect onError handler drives
+        // the v1 fallback for the picker itself.
+      } finally {
+        if (!cancelled) {
+          setMethodOptionsLoading(false);
+        }
+      }
+    };
+
+    if (slackEnabled) {
+      resolveSavedRecipients();
+    } else {
+      setMethodOptionsLoading(false);
     }
+
+    return () => {
+      cancelled = true;
+    };
+    // eslint-disable-next-line react-hooks/exhaustive-deps
   }, []);

Review Comment:
   **Suggestion:** The saved-recipient resolution effect runs only once on 
mount, but this component already supports `recipients` prop updates later. 
When `setting.recipients` changes after mount, `slackRecipients` labels are not 
re-resolved and can remain stale/incorrect. Re-run the resolution when relevant 
inputs (`method`, `recipientValue`, `options`) change. [stale reference]
   
   <details>
   <summary><b>Severity Level:</b> Major ⚠️</summary>
   
   ```mdx
   - ⚠️ SlackV2 picker shows channels that are not persisted.
   - ⚠️ Saved reports can lose SlackV2 recipients silently.
   - ⚠️ Notification summary in backend diverges from UI state.
   ```
   </details>
   <details>
   <summary><b>Steps of Reproduction ✅ </b></summary>
   
   ```mdx
   1. In AlertReportModal.tsx lines 2688-2727, open the notification panel so 
that
   notificationSettings are mapped to <NotificationMethod /> instances, each 
receiving a
   NotificationSetting with `method`, `recipients`, and `options`.
   
   2. Configure a notification with `method` set to 
`NotificationMethodOption.SlackV2` and
   select one or more channels in the SlackV2 AsyncSelect at 
NotificationMethod.tsx lines
   253-267 and 679-12; this populates `slackRecipients` via 
onSlackRecipientsChange at lines
   110-122 and persists a comma-separated channel id string into 
`setting.recipients` via
   updateNotificationSetting in AlertReportModal.tsx lines 834-859.
   
   3. Change the delivery method to Slack (SlackV1) and then back to SlackV2 
using the Select
   at NotificationMethod.tsx lines 141-157, which calls onMethodChange at lines 
72-92;
   onMethodChange resets `recipientValue`, `ccValue`, and `bccValue` and 
updates the parent
   NotificationSetting (recipients cleared), but it does not clear 
`slackRecipients`, and the
   effect that resolves saved SlackV2 recipients at lines 161-222 is declared 
with an empty
   dependency array `[]` so it never re-runs when `method`, `recipientValue`, 
or `options`
   change.
   
   4. After this toggle, the SlackV2 AsyncSelect still renders using the stale
   `slackRecipients` array while the underlying `setting.recipients` string is 
now empty;
   when the user saves, AlertReportModal.tsx lines 65-82 and 115-133 build the 
recipients
   payload from `setting.recipients`, so no SlackV2 recipient is sent even 
though the UI
   shows selected channels, demonstrating stale label state caused by the 
mount-only
   resolution effect.
   ```
   </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=712b11eedf654796823a796f88e7bce5&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=712b11eedf654796823a796f88e7bce5&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-frontend/src/features/alerts/components/NotificationMethod.tsx
   **Line:** 380:441
   **Comment:**
        *Stale Reference: The saved-recipient resolution effect runs only once 
on mount, but this component already supports `recipients` prop updates later. 
When `setting.recipients` changes after mount, `slackRecipients` labels are not 
re-resolved and can remain stale/incorrect. Re-run the resolution when relevant 
inputs (`method`, `recipientValue`, `options`) change.
   
   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%2F41998&comment_hash=c7cd3d04777461e5ec099fd8f3f8b0d70d7d8d14cf7195905fc16969d5932dba&reaction=like'>👍</a>
 | <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F41998&comment_hash=c7cd3d04777461e5ec099fd8f3f8b0d70d7d8d14cf7195905fc16969d5932dba&reaction=dislike'>👎</a>



##########
superset/reports/schemas.py:
##########
@@ -59,6 +59,9 @@
             "items": {"type": "string", "enum": ["public_channel", 
"private_channel"]},
         },
         "exact_match": {"type": "boolean"},
+        "force": {"type": "boolean"},

Review Comment:
   **Suggestion:** Exposing `force` as an accepted query parameter allows any 
caller of the Slack channels endpoint to bypass the cached channel list and 
trigger a full Slack `conversations.list` crawl repeatedly. That reintroduces 
the same rate-limit/timeout failure mode this change is trying to solve. Keep 
`force` internal-only (not user-controllable from this API) or gate it behind a 
stricter privileged path. [cache]
   
   <details>
   <summary><b>Severity Level:</b> Major ⚠️</summary>
   
   ```mdx
   ❌ Slack channel fetch bypasses cache via force flag.
   ⚠️ Large workspaces hit Slack API rate limits.
   ⚠️ Slack recipient picker can freeze on repeated force.
   ```
   </details>
   <details>
   <summary><b>Steps of Reproduction ✅ </b></summary>
   
   ```mdx
   1. Start Superset with Alerts & Reports enabled and a Slack bot token 
configured so Slack
   channel listing is active (Slack client setup and channel enumeration are 
implemented in
   `superset/utils/slack.py:79-187`).
   
   2. Call the Slack channels endpoint exposed by 
`ReportScheduleRestApi.slack_channels` via
   HTTP `GET /api/v1/report/slack_channels/` (route defined by 
`@expose("/slack_channels/",
   methods=("GET",))` at `superset/reports/api.py:628` and protected with 
`@protect()` at
   `superset/reports/api.py:63`).
   
   3. Pass a `q` query parameter containing Rison/JSON with `"force": true`, 
e.g.
   `q={"search_string":"","force":true}`; the schema 
`get_slack_channels_schema` at
   `superset/reports/schemas.py:54-62` explicitly accepts a `force` boolean, and
   `@parse_rison(get_slack_channels_schema)` at `superset/reports/api.py:64` 
deserializes it
   into `params["force"]` used at `superset/reports/api.py:685`.
   
   4. Inside `slack_channels`, the code at `superset/reports/api.py:681-127` 
calls
   `get_channels_with_search(search_string=..., types=..., exact_match=..., 
force=force)`;
   `get_channels_with_search` in `superset/utils/slack.py:197-213` forwards 
`force` into
   `get_channels(force=force, 
cache_timeout=app.config["SLACK_CACHE_TIMEOUT"])`, and
   `get_channels`’ docstring at `superset/utils/slack.py:115-133` states that 
`kwargs`
   including `"force"` are forwarded to the memoized fetch `_get_channels`, 
allowing the
   caller to bypass the cached Slack conversations list and trigger a full
   `conversations.list` crawl on every such request, reintroducing 
rate-limit/timeout risks
   for large workspaces.
   ```
   </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=812c267830f34752b5ee894325b4ea8d&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=812c267830f34752b5ee894325b4ea8d&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/reports/schemas.py
   **Line:** 62:62
   **Comment:**
        *Cache: Exposing `force` as an accepted query parameter allows any 
caller of the Slack channels endpoint to bypass the cached channel list and 
trigger a full Slack `conversations.list` crawl repeatedly. That reintroduces 
the same rate-limit/timeout failure mode this change is trying to solve. Keep 
`force` internal-only (not user-controllable from this API) or gate it behind a 
stricter privileged path.
   
   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%2F41998&comment_hash=4104060c20347506f1986a1ba010e225a0ac83298a625c560f92208de3302d1f&reaction=like'>👍</a>
 | <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F41998&comment_hash=4104060c20347506f1986a1ba010e225a0ac83298a625c560f92208de3302d1f&reaction=dislike'>👎</a>



##########
superset/reports/schemas.py:
##########
@@ -59,6 +59,9 @@
             "items": {"type": "string", "enum": ["public_channel", 
"private_channel"]},
         },
         "exact_match": {"type": "boolean"},
+        "force": {"type": "boolean"},
+        "page": {"type": "integer", "minimum": 0},
+        "page_size": {"type": "integer", "minimum": 1},

Review Comment:
   **Suggestion:** `page_size` is only bounded to be positive, but not capped, 
so callers can request extremely large pages and effectively force the backend 
to return the full filtered channel set in one response. This defeats the 
pagination protection and can still cause large payloads and browser/backend 
slowdowns. Add a strict maximum page size. [performance]
   
   <details>
   <summary><b>Severity Level:</b> Critical 🚨</summary>
   
   ```mdx
   ❌ Clients can request entire Slack channel list in one response.
   ⚠️ Large responses slow browser Slack channel picker significantly.
   ⚠️ Backend spends memory serializing huge channel arrays.
   ```
   </details>
   <details>
   <summary><b>Steps of Reproduction ✅ </b></summary>
   
   ```mdx
   1. Run Superset with Alerts & Reports enabled and SlackV2 configured; the 
frontend Slack
   recipient picker for Alerts & Reports uses the `slack_channels` API defined 
in
   `superset/reports/api.py:628-135` to enumerate channels.
   
   2. From a client (browser devtools, API script, or custom integration), 
issue `GET
   /api/v1/report/slack_channels/` with query parameter `q` containing a large 
`page_size`,
   for example `q={"page":0,"page_size":100000}`; the OpenAPI schema
   `get_slack_channels_schema` at `superset/reports/schemas.py:54-65` defines 
`"page_size":
   {"type": "integer", "minimum": 1}` without any maximum, so any positive 
integer is
   accepted.
   
   3. In `ReportScheduleRestApi.slack_channels` 
(`superset/reports/api.py:639-135`), `params
   = kwargs.get("rison", {})` is read at line 681, then `page = 
params.get("page")` and
   `page_size = params.get("page_size")` at `superset/reports/api.py:683-684`; 
the function
   fetches the full filtered channel list via `get_channels_with_search(...)` at
   `superset/reports/api.py:122-127`, which itself enumerates all cached 
channels in
   `superset/utils/slack.py:197-256` before any slicing.
   
   4. Because `page_size` is unbounded, when the client requests `page_size` 
larger than or
   equal to the total channel count, the slicing logic `start = page * 
page_size` and
   `channels = channels[start : start + page_size]` at 
`superset/reports/api.py:132-134`
   returns nearly the entire `channels` list in a single response; this 
recreates the large
   JSON payloads and frontend rendering slowdowns that the pagination change is 
intended to
   prevent, especially on workspaces with tens of thousands of Slack channels.
   ```
   </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=84a09ad519f944beae2d3ac93b53bfdd&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=84a09ad519f944beae2d3ac93b53bfdd&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/reports/schemas.py
   **Line:** 64:64
   **Comment:**
        *Performance: `page_size` is only bounded to be positive, but not 
capped, so callers can request extremely large pages and effectively force the 
backend to return the full filtered channel set in one response. This defeats 
the pagination protection and can still cause large payloads and 
browser/backend slowdowns. Add a strict maximum page size.
   
   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%2F41998&comment_hash=e8f0724ea288e047a5526797c985ffd5efcee07df70d9e9e59d4128b91f3b3d3&reaction=like'>👍</a>
 | <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F41998&comment_hash=e8f0724ea288e047a5526797c985ffd5efcee07df70d9e9e59d4128b91f3b3d3&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