fix(ui): delete prompts use data-confirm, so a quote in a name no longer runs script (#5099)

#5099 "A name containing a quote runs script when an admin clicks Delete".
Inline handlers like onclick="return confirm('Delete {{ rule.name }}?')" are
HTML-decoded before the JavaScript is parsed, so autoescaping did not stop a
name such as  x');fetch(…);//  from running.

- Every prompt (22 handlers, plus the docker prune and token revoke ones)
  is now data-confirm="…", read through dataset by one submit listener in
  base.html; nothing rendered is parsed as JavaScript.
- The remaining inline handlers take integers only (|int), and the time
  range buttons pass this.dataset.range.
- tests/test_inline_handlers.py fails on any {{ }} in an inline handler that
  is not |int, with a self-test; tests/_templates.py is the one template
  walker the template guards now share.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-06 14:30:13 -04:00
co-authored by Claude Opus 5.5
parent 737d699308
commit f47fc23265
28 changed files with 97 additions and 49 deletions
+1 -8
View File
@@ -1,16 +1,14 @@
"""The shared format filters and status_class (#5093): one way to write a size,
a rate, a span and a moment, and one grading against Settings → Thresholds."""
import pathlib
from datetime import datetime, timedelta, timezone
import jinja2
import pytest
import steward
from steward.core import formatting as f
from steward.core.settings import threshold_style_for, to_thresholds_cfg
from tests._templates import REPO as _REPO, template_files as _templates
_REPO = pathlib.Path(steward.__file__).parent.parent
TH = to_thresholds_cfg({})
NOW = datetime(2026, 10, 6, 18, 0, 0, tzinfo=timezone.utc)
@@ -88,11 +86,6 @@ def test_threshold_style_is_graded_by_status_class():
# ── every template compiles against the app's filters ────────────────────────
def _templates():
roots = [_REPO / "steward" / "templates", *(_REPO / "plugins").glob("*/templates")]
return sorted(p for root in roots for p in root.rglob("*.html"))
async def test_compiling_catches_an_unknown_filter(app):
with pytest.raises(jinja2.TemplateAssertionError, match="no_such"):
app.jinja_env.compile("{{ 1|no_such }}")