mirror of
https://github.com/apache/superset.git
synced 2026-04-19 08:04:53 +00:00
feat: add customizable brand spinners with theme integration (#34764)
Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Evan Rusackas <evan@preset.io>
This commit is contained in:
committed by
GitHub
parent
b7a193d53e
commit
b0d3f0f0d4
@@ -23,6 +23,7 @@ from superset.themes.utils import (
|
||||
_is_valid_algorithm,
|
||||
_is_valid_theme_mode,
|
||||
is_valid_theme,
|
||||
sanitize_theme_tokens,
|
||||
)
|
||||
|
||||
|
||||
@@ -75,3 +76,40 @@ def test_is_valid_algorithm(algorithm, expected):
|
||||
)
|
||||
def test_is_valid_theme(theme, expected):
|
||||
assert is_valid_theme(theme) is expected
|
||||
|
||||
|
||||
def test_sanitize_theme_tokens_with_svg():
|
||||
"""Test that theme tokens with SVG content get sanitized."""
|
||||
theme_config = {
|
||||
"token": {
|
||||
"brandSpinnerSvg": (
|
||||
'<svg><script>alert("xss")</script><rect width="10"/></svg>'
|
||||
),
|
||||
"colorPrimary": "#ff0000",
|
||||
}
|
||||
}
|
||||
result = sanitize_theme_tokens(theme_config)
|
||||
|
||||
assert "script" not in result["token"]["brandSpinnerSvg"].lower()
|
||||
assert result["token"]["colorPrimary"] == "#ff0000" # Other tokens unchanged
|
||||
|
||||
|
||||
def test_sanitize_theme_tokens_with_url():
|
||||
"""Test that theme tokens with URL get sanitized."""
|
||||
theme_config = {
|
||||
"token": {
|
||||
"brandSpinnerUrl": "javascript:alert('xss')",
|
||||
"colorPrimary": "#ff0000",
|
||||
}
|
||||
}
|
||||
result = sanitize_theme_tokens(theme_config)
|
||||
|
||||
assert result["token"]["brandSpinnerUrl"] == "" # Blocked
|
||||
assert result["token"]["colorPrimary"] == "#ff0000" # Unchanged
|
||||
|
||||
|
||||
def test_sanitize_theme_tokens_no_spinner_tokens():
|
||||
"""Test that themes without spinner tokens are unchanged."""
|
||||
theme_config = {"token": {"colorPrimary": "#ff0000", "fontFamily": "Arial"}}
|
||||
result = sanitize_theme_tokens(theme_config)
|
||||
assert result == theme_config
|
||||
|
||||
@@ -46,6 +46,8 @@ from superset.utils.core import (
|
||||
QueryObjectFilterClause,
|
||||
QuerySource,
|
||||
remove_extra_adhoc_filters,
|
||||
sanitize_svg_content,
|
||||
sanitize_url,
|
||||
)
|
||||
from tests.conftest import with_config
|
||||
|
||||
@@ -1122,3 +1124,41 @@ def test_get_stacktrace():
|
||||
except Exception:
|
||||
stacktrace = get_stacktrace()
|
||||
assert stacktrace is None
|
||||
|
||||
|
||||
def test_sanitize_svg_content_safe():
|
||||
"""Test that safe SVG content is preserved."""
|
||||
safe_svg = '<svg><rect width="10" height="10"/></svg>'
|
||||
result = sanitize_svg_content(safe_svg)
|
||||
assert "svg" in result
|
||||
assert "rect" in result
|
||||
|
||||
|
||||
def test_sanitize_svg_content_removes_scripts():
|
||||
"""Test that nh3 removes dangerous script content."""
|
||||
malicious_svg = '<svg><script>alert("xss")</script><rect/></svg>'
|
||||
result = sanitize_svg_content(malicious_svg)
|
||||
assert "script" not in result.lower()
|
||||
assert "alert" not in result
|
||||
|
||||
|
||||
def test_sanitize_url_relative():
|
||||
"""Test that relative URLs are allowed."""
|
||||
assert sanitize_url("/static/spinner.gif") == "/static/spinner.gif"
|
||||
|
||||
|
||||
def test_sanitize_url_safe_absolute():
|
||||
"""Test that safe absolute URLs are allowed."""
|
||||
assert (
|
||||
sanitize_url("https://example.com/spinner.gif")
|
||||
== "https://example.com/spinner.gif"
|
||||
)
|
||||
assert (
|
||||
sanitize_url("http://localhost/spinner.png") == "http://localhost/spinner.png"
|
||||
)
|
||||
|
||||
|
||||
def test_sanitize_url_blocks_dangerous():
|
||||
"""Test that dangerous URL schemes are blocked."""
|
||||
assert sanitize_url("javascript:alert('xss')") == ""
|
||||
assert sanitize_url("data:text/html,<script>alert(1)</script>") == ""
|
||||
|
||||
Reference in New Issue
Block a user