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.
