Compare commits

...
Author SHA1 Message Date
Elizabeth ThompsonandClaude Opus 5 997d6a85f2 fix(database): reject non-dict extra field in extra_validator
json.loads() accepts any valid JSON, not just objects, so an `extra`
payload like "123", "null", "[1,2]", "true" or '"abc"' decoded to a
non-mapping and then hit extra_.get("metadata_params", {}), raising a
raw AttributeError. Marshmallow only converts ValidationError raised by
a field validator, and the database API only catches ValidationError
around schema.load(), so the AttributeError propagated as an opaque 500
instead of a validation error.

Guard the decoded value with the same isinstance + ValidationError
pattern already used a few lines below for metadata_cache_timeout.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-09 16:43:17 +00:00
Balaji Madhan 078915f4ce docs(contributing): update legacy rst reference (#44087) 2026-09-09 23:20:02 +07:00
3 changed files with 26 additions and 2 deletions
+1 -1
View File
@@ -93,7 +93,7 @@ Look through the GitHub issues. Issues tagged with
Superset could always use better documentation,
whether as part of the official Superset docs,
in docstrings, `docs/*.rst` or even on the web as blog posts or
in docstrings, Markdown files in `docs/`, or even on the web as blog posts or
articles. See [Documentation](./howtos.md#contributing-to-documentation) for more details.
### Add Translations
+6 -1
View File
@@ -261,7 +261,7 @@ def masked_encrypted_extra_validator(value: str) -> None:
encrypted_extra_validator(value)
def extra_validator(value: str) -> str:
def extra_validator(value: str) -> str: # noqa: C901
"""
Validate that extra is a valid JSON string, and that metadata_params
keys are on the call signature for SQLAlchemy Metadata
@@ -274,6 +274,11 @@ def extra_validator(value: str) -> str:
[_("Field cannot be decoded by JSON. %(msg)s", msg=str(ex))]
) from ex
if not isinstance(extra_, dict):
raise ValidationError(
[_("Extra field must be a mapping from string keys to values.")]
)
metadata_signature = inspect.signature(MetaData)
for key in extra_.get("metadata_params", {}):
if key not in metadata_signature.parameters:
@@ -595,6 +595,25 @@ def test_extra_validator_interpolates_json_decode_error() -> None:
assert "%(" not in message
@pytest.mark.parametrize("value", [123, None, [1, 2], True, "abc"])
def test_extra_validator_rejects_non_dict_top_level_value(value: Any) -> None:
"""
Test that extra_validator rejects a top-level extra value that is valid
JSON but not a mapping (int, null, list, bool, string), instead of
letting AttributeError propagate from extra_.get("metadata_params").
"""
from superset.databases.schemas import DatabasePostSchema
schema = DatabasePostSchema()
payload = {
"database_name": "test_db",
"extra": json.dumps(value),
}
with pytest.raises(ValidationError) as exc_info:
schema.load(payload)
assert "must be a mapping" in str(exc_info.value)
def test_cache_timeout_rejects_values_below_minus_one() -> None:
"""
Test that cache_timeout rejects values less than -1.