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


##########
superset-frontend/src/explore/components/SaveModal.test.tsx:
##########
@@ -240,6 +240,83 @@ test('renders a message when saving as with new 
dashboard', () => {
   );
 });
 
+test('does not preselect an externally managed dashboard on mount', async () 
=> {
+  const dashboardId = 1;
+  fetchMock.get(
+    `glob:*/api/v1/dashboard/${dashboardId}`,
+    {
+      result: {
+        id: dashboardId,
+        dashboard_title: 'Managed Dashboard',
+        owners: [{ id: 1 }],
+        is_managed_externally: true,
+      },
+    },
+    { overwriteRoutes: true },
+  );
+
+  const store = mockStore({
+    ...initialState,
+    explore: {
+      ...initialState.explore,
+      slice: {
+        ...initialState.explore.slice,
+        dashboards: [dashboardId],
+      },
+    },
+  });
+
+  const { queryByTestId } = setup(
+    {
+      ...defaultProps,
+      dashboardId,
+    },
+    store,
+  );
+
+  await waitFor(() => {
+    expect(
+      fetchMock.callHistory.calls(`glob:*/api/v1/dashboard/${dashboardId}`),
+    ).toHaveLength(1);
+  });
+
+  const selectInput = queryByTestId('mock-async-select') as HTMLInputElement;
+  expect(selectInput?.value).toBeFalsy();

Review Comment:
   **Suggestion:** The assertion checks the mocked input's `value`, but this 
`AsyncSelect` mock never receives/binds a `value` prop, so the field stays 
empty regardless of whether a dashboard was preselected. This can let 
regressions slip through with a false-positive test. Assert the behavioral side 
effect instead (no tabs request for that dashboard), which only happens when 
preselection occurs. [logic error]
   
   <details>
   <summary><b>Severity Level:</b> Major ⚠️</summary>
   
   ```mdx
   - ⚠️ SaveModal preselection regressions can pass CI unnoticed.
   - ⚠️ Externally managed dashboard guard may silently break.
   - ⚠️ Test suite gives false confidence on mount behavior.
   ```
   </details>
   
   ```suggestion
     expect(selectInput).toBeInTheDocument();
     expect(
       
fetchMock.callHistory.calls(`glob:*/api/v1/dashboard/${dashboardId}/tabs`),
     ).toHaveLength(0);
   ```
   <details>
   <summary><b>Steps of Reproduction ✅ </b></summary>
   
   ```mdx
   1. In `superset-frontend/src/explore/components/SaveModal.test.tsx:42-46`, 
the mocked
   `AsyncSelect` renders `<input data-test="mock-async-select" ...>` and only 
forwards
   `onChange`; it does not bind any `value` prop.
   
   2. In production component code,
   `superset-frontend/src/explore/components/SaveModal.tsx:675-679`, 
`AsyncSelect` receives
   `value={this.state.dashboard}`, so preselection is represented through 
component state,
   not raw DOM input typing.
   
   3. On mount, 
`superset-frontend/src/explore/components/SaveModal.tsx:148-159` preselects a
   dashboard and calls `loadTabs(dashboardId)` when conditions pass; this is 
the behavior
   that indicates an actual preselection side effect.
   
   4. The current test assertion at `SaveModal.test.tsx:283-284` checks 
`selectInput?.value`,
   but because the mock input is uncontrolled and never receives bound value, 
that assertion
   remains falsy even if preselection logic regresses—creating a false-positive 
test.
   ```
   </details>
   <details>
   <summary><b>Prompt for AI Agent 🤖 </b></summary>
   
   ```mdx
   This is a comment left during a code review.
   
   **Path:** superset-frontend/src/explore/components/SaveModal.test.tsx
   **Line:** 284:284
   **Comment:**
        *Logic Error: The assertion checks the mocked input's `value`, but this 
`AsyncSelect` mock never receives/binds a `value` prop, so the field stays 
empty regardless of whether a dashboard was preselected. This can let 
regressions slip through with a false-positive test. Assert the behavioral side 
effect instead (no tabs request for that dashboard), which only happens when 
preselection occurs.
   
   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.
   ```
   </details>
   <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F38584&comment_hash=ae3c8b9781e83c42d6d7c9cf5805b467df976029b6aa2055cb317b1fafbc11c8&reaction=like'>👍</a>
 | <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F38584&comment_hash=ae3c8b9781e83c42d6d7c9cf5805b467df976029b6aa2055cb317b1fafbc11c8&reaction=dislike'>👎</a>



##########
superset/commands/chart/update.py:
##########
@@ -86,13 +87,19 @@ def _validate_new_dashboard_access(
         requested_dashboard_ids = {d.id for d in requested_dashboards}
 
         if new_dashboard_ids := requested_dashboard_ids - 
existing_dashboard_ids:
-            # For NEW dashboard relationships, verify user has access
+            # For NEW dashboard relationships, verify user has access first
+            # to avoid leaking information about inaccessible dashboards
             accessible_dashboards = 
DashboardDAO.find_by_ids(list(new_dashboard_ids))
             accessible_dashboard_ids = {d.id for d in accessible_dashboards}
             unauthorized_dashboard_ids = new_dashboard_ids - 
accessible_dashboard_ids
 
             if unauthorized_dashboard_ids:
                 exceptions.append(DashboardsNotFoundValidationError())
+                return
+
+            for dash in accessible_dashboards:
+                if dash.is_managed_externally:

Review Comment:
   **Suggestion:** New dashboard relationships are only checked for visibility, 
not edit permission. A user with read access to a published dashboard can still 
attach a chart to it, which modifies that dashboard without ownership rights. 
Align this with chart creation logic by also requiring dashboard ownership 
before allowing the relationship. [logic error]
   
   <details>
   <summary><b>Severity Level:</b> Critical 🚨</summary>
   
   ```mdx
   - ❌ PUT /api/v1/chart allows unauthorized dashboard chart additions.
   - ⚠️ Published dashboards become mutable by non-owner chart editors.
   - ⚠️ Update/create permission behavior diverges across chart commands.
   ```
   </details>
   
   ```suggestion
                               if dash.is_managed_externally or not 
security_manager.is_owner(dash):
   ```
   <details>
   <summary><b>Steps of Reproduction ✅ </b></summary>
   
   ```mdx
   1. Use a non-admin user who owns a chart but does not own a published 
dashboard; this is
   realistic because `DashboardAccessFilter` explicitly includes published 
dashboards for
   non-owners (`superset/dashboards/filters.py:104-109`, `:132-139`, 
`:185-190`).
   
   2. Call chart update endpoint `PUT /api/v1/chart/<pk>` 
(`superset/charts/api.py:389`),
   sending `dashboards` containing that published dashboard ID; request is 
executed via
   `UpdateChartCommand(pk, item).run()` at `superset/charts/api.py:437`.
   
   3. In validation, requested dashboard IDs are first loaded with 
`skip_base_filter=True`
   (`superset/commands/chart/update.py:154-156`), then 
`_validate_new_dashboard_access()` is
   called (`superset/commands/chart/update.py:162`).
   
   4. `_validate_new_dashboard_access()` re-fetches only new dashboard IDs with 
base filter
   (`superset/commands/chart/update.py:92`), and only blocks 
`is_managed_externally`
   (`superset/commands/chart/update.py:101-102`), so non-owner writable check 
is missing and
   request succeeds (no `DashboardsForbiddenError`), unlike create flow which 
enforces
   ownership (`superset/commands/chart/create.py:74-75`).
   ```
   </details>
   <details>
   <summary><b>Prompt for AI Agent 🤖 </b></summary>
   
   ```mdx
   This is a comment left during a code review.
   
   **Path:** superset/commands/chart/update.py
   **Line:** 101:101
   **Comment:**
        *Logic Error: New dashboard relationships are only checked for 
visibility, not edit permission. A user with read access to a published 
dashboard can still attach a chart to it, which modifies that dashboard without 
ownership rights. Align this with chart creation logic by also requiring 
dashboard ownership before allowing the relationship.
   
   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.
   ```
   </details>
   <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F38584&comment_hash=07847d94e03a40760f80e7f5f1bda043e4c368ba9ee0b638833e025b13de70da&reaction=like'>👍</a>
 | <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F38584&comment_hash=07847d94e03a40760f80e7f5f1bda043e4c368ba9ee0b638833e025b13de70da&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