This is an automated email from the ASF dual-hosted git repository.

eschutho pushed a commit to branch 
fix-oauth2-config-encrypted-extra-decode-error
in repository https://gitbox.apache.org/repos/asf/superset.git

commit d09a7803af731dde264ba094c39b6f8094f86fd6
Author: Elizabeth Thompson <[email protected]>
AuthorDate: Fri Sep 25 16:40:15 2026 +0000

    fix(database): catch JSONDecodeError in get_oauth2_config
    
    Database.get_oauth2_config() calls json.loads(self.encrypted_extra)
    without any exception handling. If encrypted_extra contains malformed
    JSON (hand-edited config, partial write, migration artifact), a raw
    simplejson.JSONDecodeError (a ValueError, not a SupersetException)
    escapes through _get_sqla_engine on every connection attempt.
    
    Wrap the json.loads call in a try/except and raise
    SupersetGenericDBErrorException instead, matching the fix pattern
    from PR #44616.
    
    Co-Authored-By: Claude Opus 4.6 <[email protected]>
---
 superset/models/core.py              |  7 ++++++-
 tests/unit_tests/models/core_test.py | 21 ++++++++++++++++++++-
 2 files changed, 26 insertions(+), 2 deletions(-)

diff --git a/superset/models/core.py b/superset/models/core.py
index 5712a306f6a..ef5a7109cd2 100755
--- a/superset/models/core.py
+++ b/superset/models/core.py
@@ -69,6 +69,7 @@ from superset.constants import LRU_CACHE_MAX_SIZE, 
PASSWORD_MASK
 from superset.databases.error_provenance import mark_database_engine_error
 from superset.databases.utils import make_url_safe
 from superset.db_engine_specs.base import MetricType, TimeGrain
+from superset.exceptions import SupersetGenericDBErrorException
 from superset.extensions import (
     cache_manager,
     encrypted_field_factory,
@@ -1508,7 +1509,11 @@ class Database(CoreDatabase, AuditMixinNullable, 
ImportExportMixin):  # pylint:
         admins to create custom OAuth2 clients from the Superset UI, and 
assign them to
         specific databases.
         """
-        encrypted_extra = json.loads(self.encrypted_extra or "{}")
+        try:
+            encrypted_extra = json.loads(self.encrypted_extra or "{}")
+        except json.JSONDecodeError as ex:
+            logger.error(ex, exc_info=True)
+            raise SupersetGenericDBErrorException(message=str(ex)) from ex
         if oauth2_client_info := encrypted_extra.get("oauth2_client_info"):
             schema = OAuth2ClientConfigSchema()
             client_config = schema.load(oauth2_client_info)
diff --git a/tests/unit_tests/models/core_test.py 
b/tests/unit_tests/models/core_test.py
index c614e44f401..94fb6254605 100644
--- a/tests/unit_tests/models/core_test.py
+++ b/tests/unit_tests/models/core_test.py
@@ -40,7 +40,11 @@ from sqlalchemy.sql import Select
 from superset.connectors.sqla.models import SqlaTable, TableColumn
 from superset.databases.error_provenance import mark_database_engine_error
 from superset.errors import SupersetErrorType
-from superset.exceptions import OAuth2Error, OAuth2RedirectError
+from superset.exceptions import (
+    OAuth2Error,
+    OAuth2RedirectError,
+    SupersetGenericDBErrorException,
+)
 from superset.models.core import Database
 from superset.sql.parse import LimitMethod, Table
 from superset.utils import json
@@ -1247,6 +1251,21 @@ def test_get_oauth2_config_redirect_uri_from_config(
     assert config["redirect_uri"] == custom_redirect_uri
 
 
+def test_get_oauth2_config_malformed_encrypted_extra(app_context: None) -> 
None:
+    """
+    Test that malformed JSON in ``encrypted_extra`` raises a Superset exception
+    instead of leaking the raw ``JSONDecodeError``.
+    """
+    database = Database(
+        database_name="db",
+        sqlalchemy_uri="postgresql://user:password@host:5432/examples",
+    )
+    database.encrypted_extra = "{not valid json"
+
+    with pytest.raises(SupersetGenericDBErrorException):
+        database.get_oauth2_config()
+
+
 def test_raw_connection_oauth_engine(mocker: MockerFixture) -> None:
     """
     Test that we can start OAuth2 from `raw_connection()` errors.

Reply via email to