From 8b5b0f8ef5d362ac90dd09b0917dab9f3e2687ea Mon Sep 17 00:00:00 2001 From: ZdenekSrotyr <139972147+ZdenekSrotyr@users.noreply.github.com> Date: Thu, 14 May 2026 22:27:34 +0200 Subject: [PATCH] fix(web): render in /me/activity hero subtitle instead of escaping it (#312) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The subtitle was built by ~-concatenating a Markup operand (user.email | e) with HTML string literals. Under autoescaping, Jinja2's markup_join escapes every non-Markup part once it hits a Markup operand — so the literal tags became <strong> and the page showed literal "..." text around the email. The | safe in _page_hero.html was too late to undo it. Switch to {% set %}...{% endset %} block capture: the literal stays HTML while {{ user.email }} is still autoescaped. Regression test asserts the tags render and a hostile email stays escaped. --- CHANGELOG.md | 9 +++++++++ app/web/templates/me_activity.html | 5 ++++- tests/test_web_ui.py | 13 +++++++++++++ 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6ca802d..a5af2e0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,15 @@ CalVer image tags (`stable-YYYY.MM.N`, `dev-YYYY.MM.N`) are produced for every C ## [Unreleased] +### Fixed +- `/me/activity` hero subtitle showed literal `` tags + around the user's email instead of rendering them bold. The subtitle + was built by `~`-concatenating a `Markup` operand (`user.email | e`) + with HTML string literals, which made Jinja2's `markup_join` escape + the literal tags too. Switched to `{% set %}…{% endset %}` block + capture so the literal `` stays HTML while the email is still + autoescaped. + ### Internal - CI test suite sharded for speed. The `test` job in `.github/workflows/ci.yml` is now a `test-shard` matrix — 4 parallel jobs via `pytest-split`, balanced by a committed `.test_durations` file — aggregated into a single `test` status check so branch protection needs no change. The duplicate full-suite `test` job in `release.yml` is removed (it re-ran the same ~10 min suite a second time on every push to main/feature branches); `release.yml` is now image-build only, with the advisory ruff/mypy steps moved to a lean `lint` job in `ci.yml`. Net: ~10 min → ~3 min wall-clock per push, and the suite runs once instead of twice. Adds `pytest-split` to the `dev` extra. diff --git a/app/web/templates/me_activity.html b/app/web/templates/me_activity.html index 757a736..cef7eb5 100644 --- a/app/web/templates/me_activity.html +++ b/app/web/templates/me_activity.html @@ -81,7 +81,10 @@
{% set page_hero_eyebrow = "Profile" %} {% set page_hero_title = "My activity" %} - {% set page_hero_subtitle = "Sessions, token usage, data access, and sync activity for " ~ (user.email | e) ~ "." %} + {# Block-capture so the literal stays HTML while {{ user.email }} + is still autoescaped. `~`-concatenating a Markup operand (user.email | e) + made Jinja2's markup_join escape the literal tags too. #} + {% set page_hero_subtitle %}Sessions, token usage, data access, and sync activity for {{ user.email }}.{% endset %} {% include "_page_hero.html" %}