aminghadersohi commented on code in PR #45575:
URL: https://github.com/apache/superset/pull/45575#discussion_r4367066006


##########
superset/mcp_service/chart/schemas.py:
##########
@@ -6396,16 +6416,24 @@ def _detect_chart_name_sanitization(cls, data: Any) -> 
Any:
 
     @field_validator("chart_name")
     @classmethod
-    def sanitize_chart_name(cls, v: str | None) -> str | None:
-        """Sanitize chart name to prevent XSS attacks."""
-        try:
-            return sanitize_user_input(
-                v, "Chart name", max_length=255, allow_empty=True
-            )
-        except ValueError as ex:
-            raise PydanticCustomError(
-                "unsafe_text", "{error}", {"error": str(ex)}
-            ) from ex
+    def normalize_blank_chart_name(cls, v: str | None) -> str | None:
+        """Keep the optional-name fallback; nonblank names are sanitized 
above."""
+        return v if v and v.strip() else None

Review Comment:
   You're right: my earlier theme sibling entry was incorrect. Fixed in 
0c80cb2f93830711849b06965c4e28a3f4ce2f00; final head 
57260a2b4544fb3c71004775194a5d8ca897dfed (documentation/test alignment): 
create_theme rejects blank theme_name before the 250-character cap, including 
the reported 300-space input. I also gave 
create_dataset_metric/update_dataset_metric metric_name and update_dataset 
table_name the same blank-first behavior, rather than weakening the 
documentation promise. Nonblank names retain their whitespace, length limits, 
and malformed-input errors; omitted updates and explicit invalid null names 
keep their existing behavior.
   
   Regression tests added in 
tests/unit_tests/mcp_service/test_sanitization_warning_inputs.py:
   - test_documented_blank_errors_precede_length systematically covers all 
eight request fields with a documented blank-error promise: 
update_dashboard.dashboard_title (500), duplicate_dashboard.dashboard_title 
(500), create_virtual_dataset.dataset_name (250), create_theme.theme_name 
(250), create_dataset_metric.metric_name (255), 
update_dataset_metric.metric_name (255), update_dataset.table_name (250), and 
save_sql_query.label (256). Each is tested with " " * (cap + 1) as str, bytes 
and bytearray, plus Unicode whitespace. The four affected requests produce 24 
failures before this commit and pass after; the other 24 cases are 
already-passing sibling controls.
   - test_required_name_over_cap_blank_wire_reason pins the exact MCP response, 
including "Text must not be empty" at the corresponding name field, for cap+1 
and cap+50 blanks. Eight cases fail before/pass after (including theme_name 
with 300 spaces); four existing-behavior sibling controls pass both times.
   - test_documented_name_nonblank_length_boundary, 
test_literal_names_keep_nonblank_whitespace, and 
test_literal_names_reject_malformed_inputs retain 84 passing controls for 
exact/over-limit nonblank names, whitespace preservation, and native 
field-located type/UTF-8 errors.
   
   The same 144-case regression suite ran in Docker against untouched source at 
705c6f0bc395800d6b5fee03d5bef0a9830b1852 (32 failed / 112 passed) and this 
commit (144 passed). Command: `python -m pytest -q 
tests/unit_tests/mcp_service/test_sanitization_warning_inputs.py -k 
'documented_blank_errors_precede_length or 
documented_name_nonblank_length_boundary or 
required_name_over_cap_blank_wire_reason or literal_names_'`.
   
   Full Docker MCP run: 13,245 passed / 12 skipped with `python -m pytest -n 2 
--dist loadfile tests/unit_tests/mcp_service -m 'not manual and not 
llm_compliance' --cache-clear -o cache_dir=/tmp/pytest-cache --maxfail=20`. The 
touched regression file passed all 1,737 tests. The updated 
test_builtin_name_validation_documented_for_administrators also fails against 
the original documentation and passes against the clarified documentation; its 
whitespace-normalized assertion avoids depending on Markdown line wrapping.
   
   Changed-file pre-commit and explicit `pre-commit run mypy` passed; the three 
existing frontend Jest suites passed (32 tests). Real-LLM checks were excluded 
(OpenRouter disabled).
   
   I searched `rg -n 'max_length|empty_text' superset/mcp_service -g 
'*schemas.py'`, inventoried all 140 explicit max_length field declarations 
(including nested/response schemas), compared the documentation's named 
blank-error contracts, and searched all callers of the changed request models. 
The eight promised fields and adjacent paths are all listed below.
   
   Siblings checked:
   - superset/mcp_service/theme/schemas.py:138 — fixed in 
0c80cb2f93830711849b06965c4e28a3f4ce2f00 (CreateThemeRequest.theme_name, cap 
250).
   - superset/mcp_service/dataset/schemas.py:701 — fixed in 
0c80cb2f93830711849b06965c4e28a3f4ce2f00 (DatasetMetricProperties.metric_name, 
shared blank-first validator, cap 255).
   - superset/mcp_service/dataset/schemas.py:809 — fixed in 
0c80cb2f93830711849b06965c4e28a3f4ce2f00 
(UpdateDatasetMetricRequest.metric_name inherits that validator).
   - superset/mcp_service/dataset/schemas.py:820 — fixed in 
0c80cb2f93830711849b06965c4e28a3f4ce2f00 
(CreateDatasetMetricRequest.metric_name inherits that validator despite 
overriding the field).
   - superset/mcp_service/dataset/schemas.py:1025 — fixed in 
0c80cb2f93830711849b06965c4e28a3f4ce2f00 (UpdateDatasetRequest.table_name, cap 
250).
   - superset/mcp_service/dataset/schemas.py:580 — not affected: 
CreateVirtualDatasetRequest.dataset_name (cap 250) already decodes bytes, 
rejects blanks and trims before its cap; included in the same regression sweep.
   - superset/mcp_service/dashboard/schemas.py:926 — not affected: 
UpdateDashboardRequest.dashboard_title (cap 500) already rejects blanks before 
its cap; included in the same regression sweep.
   - superset/mcp_service/dashboard/schemas.py:1487 — not affected: 
DuplicateDashboardRequest.dashboard_title (cap 500) already rejects blanks 
before its cap; included in the same regression sweep.
   - superset/mcp_service/sql_lab/schemas.py:233 — not affected: 
SaveSqlQueryRequest.label (cap 256) already decodes bytes and rejects blanks 
before its cap; included in the same regression sweep.
   - superset/mcp_service/chart/schemas.py:6352 — not affected: ChartNameMixin 
already normalizes blank chart_name to None before its cap for both 
GenerateChartRequest and UpdateChartRequest; 
test_blank_titles_normalize_before_length covers strings, bytes, bytearrays and 
all four aliases.
   - superset/mcp_service/dashboard/schemas.py:781 — not affected: 
GenerateDashboardRequest uses its documented optional-title fallback rather 
than an empty-text error; test_blank_titles_normalize_before_length covers 
strings, bytes, bytearrays and aliases.
   - superset/mcp_service/dataset/schemas.py:506 — not affected: 
CreateDatasetRequest.table_name trims before its cap and uses its min_length 
error for blanks, not the blank-error promise naming create_virtual_dataset and 
update_dataset; schema/catalog blanks normalize to None before their caps.
   - superset/mcp_service/dataset/schemas.py:458 — not affected: nested 
CreateDatasetMetric.metric_name has no max_length and is not the 
create_dataset_metric/update_dataset_metric tool request named in the 
documentation.
   - superset/mcp_service/sql_lab/schemas.py:301 — not affected: 
OpenSqlLabRequest.title normalizes blanks to None before its cap, not the 
blank-error contract for save_sql_query.label.
   - superset/mcp_service/dashboard/schemas.py:1093 — not affected: 
UpdateDashboardRequest.slug has a separate blank-clears-slug contract and 
normalizes before its cap, not the dashboard_title blank-error promise.
   - superset/mcp_service/theme/tool/create_theme.py:61 — not affected: 
consumes the validated CreateThemeRequest; no separate raw-name normalization 
path.
   - superset/mcp_service/dataset/tool/create_dataset_metric.py:47 — not 
affected: consumes the validated CreateDatasetMetricRequest and its updates(), 
with no separate raw-name normalization path.
   - superset/mcp_service/dataset/tool/update_dataset_metric.py:110 — not 
affected: consumes the validated UpdateDatasetMetricRequest and its updates(), 
with no separate raw-name normalization path.
   - superset/mcp_service/dataset/tool/update_dataset.py:80 — not affected: 
consumes the validated UpdateDatasetRequest and its updates(), with no separate 
raw-name normalization path.
   - superset/themes/schemas.py — not affected: the REST theme endpoint uses 
separate Marshmallow validation; the documented promise here is for MCP 
requests.
   - superset/datasets/schemas.py — not affected: REST dataset/metric schemas 
do not invoke these MCP validators; their validation contract is unchanged.
   - docs/admin_docs/configuration/mcp-server.mdx:2457 — fixed in 
57260a2b4544fb3c71004775194a5d8ca897dfed (blank-first ordering is explicit, 
nonblank whitespace preservation is precise, and the comparison names virtual 
datasets rather than physical table names).
   - tests/unit_tests/mcp_service/test_sanitization_warning_inputs.py:1376 — 
fixed in 57260a2b4544fb3c71004775194a5d8ca897dfed (the documentation assertion 
checks the clarified contract and ignores Markdown line wrapping).
   



-- 
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