korbit-ai[bot] commented on code in PR #34560:
URL: https://github.com/apache/superset/pull/34560#discussion_r2270915032


##########
superset/migrations/versions/2025-08-05_14-38_c233f5365c9e_is_system_default_is_system_dark.py:
##########
@@ -0,0 +1,87 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+"""is_system_default-is_system_dark
+
+Revision ID: c233f5365c9e
+Revises: cd1fb11291f2
+Create Date: 2025-08-05 14:38:55.782777
+
+"""
+
+import sqlalchemy as sa
+from alembic import op
+from sqlalchemy import false
+
+from superset.migrations.shared.utils import (
+    add_columns,
+    create_index,
+    drop_columns,
+    drop_index,
+)
+
+# revision identifiers, used by Alembic.
+revision = "c233f5365c9e"
+down_revision = "cd1fb11291f2"
+
+
+def upgrade():
+    # Add columns as nullable first
+    add_columns(
+        "themes",
+        sa.Column("is_system_default", sa.Boolean(), nullable=True),
+        sa.Column("is_system_dark", sa.Boolean(), nullable=True),
+    )
+
+    # Update existing rows to have False values using SQLAlchemy
+    connection = op.get_bind()
+    themes_table = sa.table(
+        "themes",
+        sa.column("is_system_default", sa.Boolean()),
+        sa.column("is_system_dark", sa.Boolean()),
+    )
+
+    connection.execute(
+        themes_table.update()
+        .where(themes_table.c.is_system_default.is_(None))
+        .values(is_system_default=false())
+    )

Review Comment:
   ### Missing Transaction in Theme Migration Updates <sub>![category 
Functionality](https://img.shields.io/badge/Functionality-0284c7)</sub>
   
   <details>
     <summary>Tell me more</summary>
   
   ###### What is the issue?
   The update statements are not wrapped in a transaction, which could lead to 
partial updates if the migration fails midway.
   
   
   ###### Why this matters
   If the migration fails after the first update but before the second one, the 
database will be left in an inconsistent state with only one column updated.
   
   ###### Suggested change ∙ *Feature Preview*
   Wrap both update statements in a transaction:
   ```python
   with op.get_context().begin_transaction():
       connection.execute(
           themes_table.update()
           .where(themes_table.c.is_system_default.is_(None))
           .values(is_system_default=false())
       )
   
       connection.execute(
           themes_table.update()
           .where(themes_table.c.is_system_dark.is_(None))
           .values(is_system_dark=false())
       )
   ```
   
   
   ###### Provide feedback to improve future suggestions
   [![Nice 
Catch](https://img.shields.io/badge/👍%20Nice%20Catch-71BC78)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/45836de3-d77f-4342-97f8-fad60709b469/upvote)
 
[![Incorrect](https://img.shields.io/badge/👎%20Incorrect-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/45836de3-d77f-4342-97f8-fad60709b469?what_not_true=true)
  [![Not in 
Scope](https://img.shields.io/badge/👎%20Out%20of%20PR%20scope-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/45836de3-d77f-4342-97f8-fad60709b469?what_out_of_scope=true)
 [![Not in coding 
standard](https://img.shields.io/badge/👎%20Not%20in%20our%20standards-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/45836de3-d77f-4342-97f8-fad60709b469?what_not_in_standard=true)
 
[![Other](https://img.shields.io/badge/👎%20Other-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/45836de3-d77f-4342-97f8-fad60709b469)
   </details>
   
   <sub>
   
   💬 Looking for more details? Reply to this comment to chat with Korbit.
   </sub>
   
   <!--- korbi internal id:e5dd38eb-663c-4f51-bc09-18393b96c65d -->
   
   
   [](e5dd38eb-663c-4f51-bc09-18393b96c65d)



##########
superset-frontend/src/pages/ThemeList/index.tsx:
##########
@@ -111,6 +119,13 @@ function ThemesList({
   const canImport = hasPerm('can_write');
   const canApply = hasPerm('can_write'); // Only users with write permission 
can apply themes
 
+  // Get theme settings from bootstrap data
+  const bootstrapData = getBootstrapData();
+  const themeData = bootstrapData?.common?.theme || {};

Review Comment:
   ### Unsafe Type Casting of Security-Critical Permission Data <sub>![category 
Security](https://img.shields.io/badge/Security-e11d48)</sub>
   
   <details>
     <summary>Tell me more</summary>
   
   ###### What is the issue?
   The themeData object is being type cast with 'as any' which bypasses 
TypeScript's type checking when accessing enableUiThemeAdministration.
   
   
   ###### Why this matters
   Using 'as any' to bypass type checking could allow unauthorized access to 
theme administration features if the bootstrap data was tampered with 
client-side.
   
   ###### Suggested change ∙ *Feature Preview*
   ```typescript
   interface ThemeData {
     enableUiThemeAdministration?: boolean;
   }
   const themeData = (bootstrapData?.common?.theme || {}) as ThemeData;
   ```
   
   
   ###### Provide feedback to improve future suggestions
   [![Nice 
Catch](https://img.shields.io/badge/👍%20Nice%20Catch-71BC78)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/6a07c9a7-51e9-4209-ad1c-3df0593d9900/upvote)
 
[![Incorrect](https://img.shields.io/badge/👎%20Incorrect-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/6a07c9a7-51e9-4209-ad1c-3df0593d9900?what_not_true=true)
  [![Not in 
Scope](https://img.shields.io/badge/👎%20Out%20of%20PR%20scope-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/6a07c9a7-51e9-4209-ad1c-3df0593d9900?what_out_of_scope=true)
 [![Not in coding 
standard](https://img.shields.io/badge/👎%20Not%20in%20our%20standards-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/6a07c9a7-51e9-4209-ad1c-3df0593d9900?what_not_in_standard=true)
 
[![Other](https://img.shields.io/badge/👎%20Other-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/6a07c9a7-51e9-4209-ad1c-3df0593d9900)
   </details>
   
   <sub>
   
   💬 Looking for more details? Reply to this comment to chat with Korbit.
   </sub>
   
   <!--- korbi internal id:deaa8e2b-60c0-4ad0-b593-3efa6a5952a8 -->
   
   
   [](deaa8e2b-60c0-4ad0-b593-3efa6a5952a8)



##########
superset/migrations/versions/2025-08-05_14-38_c233f5365c9e_is_system_default_is_system_dark.py:
##########
@@ -0,0 +1,87 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+"""is_system_default-is_system_dark
+
+Revision ID: c233f5365c9e
+Revises: cd1fb11291f2
+Create Date: 2025-08-05 14:38:55.782777
+
+"""
+
+import sqlalchemy as sa
+from alembic import op
+from sqlalchemy import false
+
+from superset.migrations.shared.utils import (
+    add_columns,
+    create_index,
+    drop_columns,
+    drop_index,
+)
+
+# revision identifiers, used by Alembic.
+revision = "c233f5365c9e"
+down_revision = "cd1fb11291f2"
+
+
+def upgrade():
+    # Add columns as nullable first
+    add_columns(
+        "themes",
+        sa.Column("is_system_default", sa.Boolean(), nullable=True),
+        sa.Column("is_system_dark", sa.Boolean(), nullable=True),
+    )
+
+    # Update existing rows to have False values using SQLAlchemy
+    connection = op.get_bind()
+    themes_table = sa.table(
+        "themes",
+        sa.column("is_system_default", sa.Boolean()),
+        sa.column("is_system_dark", sa.Boolean()),
+    )
+
+    connection.execute(
+        themes_table.update()
+        .where(themes_table.c.is_system_default.is_(None))
+        .values(is_system_default=false())
+    )
+
+    connection.execute(
+        themes_table.update()
+        .where(themes_table.c.is_system_dark.is_(None))
+        .values(is_system_dark=false())
+    )
+
+    # Now make the columns non-nullable
+    # MySQL requires explicit type specification for CHANGE/MODIFY operations
+    with op.batch_alter_table("themes") as batch_op:
+        batch_op.alter_column(
+            "is_system_default", existing_type=sa.Boolean(), nullable=False
+        )
+        batch_op.alter_column(
+            "is_system_dark", existing_type=sa.Boolean(), nullable=False
+        )
+
+    # Create indexes
+    create_index("themes", "idx_theme_is_system_default", 
["is_system_default"])
+    create_index("themes", "idx_theme_is_system_dark", ["is_system_dark"])
+
+
+def downgrade():
+    drop_index("themes", "idx_theme_is_system_default")
+    drop_index("themes", "idx_theme_is_system_dark")
+    drop_columns("themes", "is_system_dark", "is_system_default")

Review Comment:
   ### Data Loss in Theme Migration Downgrade <sub>![category 
Functionality](https://img.shields.io/badge/Functionality-0284c7)</sub>
   
   <details>
     <summary>Tell me more</summary>
   
   ###### What is the issue?
   The downgrade function does not preserve the data from the dropped columns, 
which could lead to data loss if a rollback is needed.
   
   
   ###### Why this matters
   If the migration needs to be rolled back, all theme configuration data for 
system default and dark mode will be permanently lost.
   
   ###### Suggested change ∙ *Feature Preview*
   Add data backup before dropping columns:
   ```python
   def downgrade():
       # Optionally backup data if needed for future migrations
       connection = op.get_bind()
       themes_table = sa.Table('themes', sa.MetaData(), 
           sa.Column('is_system_default', sa.Boolean()),
           sa.Column('is_system_dark', sa.Boolean())
       )
       backup_data = connection.execute(
           sa.select([
               themes_table.c.is_system_default,
               themes_table.c.is_system_dark
           ])
       ).fetchall()
       
       # Store backup data in a new table or file if needed
       
       drop_index("themes", "idx_theme_is_system_default")
       drop_index("themes", "idx_theme_is_system_dark")
       drop_columns("themes", "is_system_dark", "is_system_default")
   ```
   
   
   ###### Provide feedback to improve future suggestions
   [![Nice 
Catch](https://img.shields.io/badge/👍%20Nice%20Catch-71BC78)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/7ca8d4bd-189a-46b1-af05-9c170e0504f7/upvote)
 
[![Incorrect](https://img.shields.io/badge/👎%20Incorrect-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/7ca8d4bd-189a-46b1-af05-9c170e0504f7?what_not_true=true)
  [![Not in 
Scope](https://img.shields.io/badge/👎%20Out%20of%20PR%20scope-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/7ca8d4bd-189a-46b1-af05-9c170e0504f7?what_out_of_scope=true)
 [![Not in coding 
standard](https://img.shields.io/badge/👎%20Not%20in%20our%20standards-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/7ca8d4bd-189a-46b1-af05-9c170e0504f7?what_not_in_standard=true)
 
[![Other](https://img.shields.io/badge/👎%20Other-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/7ca8d4bd-189a-46b1-af05-9c170e0504f7)
   </details>
   
   <sub>
   
   💬 Looking for more details? Reply to this comment to chat with Korbit.
   </sub>
   
   <!--- korbi internal id:57544526-3c28-4509-be1c-762e72b745b7 -->
   
   
   [](57544526-3c28-4509-be1c-762e72b745b7)



##########
superset-frontend/src/theme/ThemeController.ts:
##########
@@ -128,18 +119,15 @@ export class ThemeController {
     const {
       bootstrapDefaultTheme,
       bootstrapDarkTheme,
-      bootstrapThemeSettings,
       hasCustomThemes,
     }: BootstrapThemeData = this.loadBootstrapData();
 
     this.hasCustomThemes = hasCustomThemes;
-    this.themeSettings = bootstrapThemeSettings || {};
 
     // Set themes based on bootstrap data availability
     if (this.hasCustomThemes) {
-      this.darkTheme = bootstrapDarkTheme || bootstrapDefaultTheme || null;
-      this.defaultTheme =
-        bootstrapDefaultTheme || bootstrapDarkTheme || defaultTheme;
+      this.darkTheme = bootstrapDarkTheme;
+      this.defaultTheme = bootstrapDefaultTheme || defaultTheme;
     } else {

Review Comment:
   ### Missing Dark Theme Null Check <sub>![category 
Functionality](https://img.shields.io/badge/Functionality-0284c7)</sub>
   
   <details>
     <summary>Tell me more</summary>
   
   ###### What is the issue?
   The controller sets darkTheme unconditionally when hasCustomThemes is true, 
without checking if bootstrapDarkTheme is null, which could lead to unexpected 
behavior.
   
   
   ###### Why this matters
   This could cause the dark theme functionality to appear available when it's 
not, leading to theme switching UI being enabled when it shouldn't be.
   
   ###### Suggested change ∙ *Feature Preview*
   Add a null check for bootstrapDarkTheme to ensure proper initialization:
   ```typescript
   if (this.hasCustomThemes) {
     this.darkTheme = bootstrapDarkTheme || null;
     this.defaultTheme = bootstrapDefaultTheme || defaultTheme;
   }
   ```
   
   
   ###### Provide feedback to improve future suggestions
   [![Nice 
Catch](https://img.shields.io/badge/👍%20Nice%20Catch-71BC78)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/cd5909c9-8dec-4034-ad0d-beb41ebf764c/upvote)
 
[![Incorrect](https://img.shields.io/badge/👎%20Incorrect-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/cd5909c9-8dec-4034-ad0d-beb41ebf764c?what_not_true=true)
  [![Not in 
Scope](https://img.shields.io/badge/👎%20Out%20of%20PR%20scope-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/cd5909c9-8dec-4034-ad0d-beb41ebf764c?what_out_of_scope=true)
 [![Not in coding 
standard](https://img.shields.io/badge/👎%20Not%20in%20our%20standards-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/cd5909c9-8dec-4034-ad0d-beb41ebf764c?what_not_in_standard=true)
 
[![Other](https://img.shields.io/badge/👎%20Other-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/cd5909c9-8dec-4034-ad0d-beb41ebf764c)
   </details>
   
   <sub>
   
   💬 Looking for more details? Reply to this comment to chat with Korbit.
   </sub>
   
   <!--- korbi internal id:e8900e4b-4288-4f4d-ad81-bd702ef9d2db -->
   
   
   [](e8900e4b-4288-4f4d-ad81-bd702ef9d2db)



-- 
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: notifications-unsubscr...@superset.apache.org

For queries about this service, please contact Infrastructure at:
us...@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscr...@superset.apache.org
For additional commands, e-mail: notifications-h...@superset.apache.org

Reply via email to