Repository navigation
Escape conference text in inline JavaScript and HTML attributes - #513
Conversation
Liquid pastes values verbatim, so `place: '{{conf.place}}'` rendered as
`place: 'Abidjan, Côte d'Ivoire'` and the front page's per-conference
script failed to parse. The curly apostrophe in #512 fixed the name but
not the place, so the front page and the PyCon Côte d'Ivoire page still
threw a SyntaxError.
Every conference name, place and link that reaches JavaScript now goes
through jsonify, the way head.html and the JSON-LD block already do.
tests/test_template_escaping.py fails when a free-text conference field
lands in a script without jsonify or slugify, or when a jsonify'd value
is wrapped in quotes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YSanwpb5BXzbhLxMFyz9yS
CodeQL (py/bad-tag-filter) flagged that `</script>` misses `</script >`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YSanwpb5BXzbhLxMFyz9yS
|
Routine review RequestNo linked issue; the request is the PR description: route every conference name, place and link that reaches inline JavaScript through Checked against
Needs your decision
FindingsImportant: None. Nits
TestsThe new test does test the invariant. It scans every Base ( Change, full suite (REVIEW.md
End-to-end: I ran On the front page ( CI on the head: Bounds
Generated by Claude Code |
|
Decision 1 is settled by 730439f: the end tag is now Generated by Claude Code |
Free text in a double-quoted attribute ended the value at the first ", so data-conf-name, data-location, aria-label, meta content and the share and map links now go through escape, or url_encode where the value is part of a URL. The share links replace url_encode's + with %20, which mailto: needs and the other targets accept. URL fields stay as they are: the schema validates them and pydantic percent-encodes quotes in them. The front page's action bar got the name and place through include parameters, and the extra places through a for loop, so the template test now follows include parameters and variables set with assign or for. calendar.js never reset `extended`, so every conference after the first extended CfP was labelled "(extended)" too: 66 labels for 16 extended CfPs. It now resets the way calendar-deadlines.ics already does. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YSanwpb5BXzbhLxMFyz9yS
Problem
Liquid pastes values into templates verbatim.
index.htmlbuilt the calendar button withplace: '{{conf.place}}', which rendered asand the front page's per-conference inline script failed to parse. The curly apostrophe in #512 fixed
conference, butplacestill holds the ASCII apostrophe, so on currentmainthe front page and/conference/pycon-cote-d-ivoire-2027/both throwSyntaxError: Unexpected identifier 'Ivoire'(confirmed by building the site and parsing every inline<script>with Node).The same verbatim pasting puts names and places into double-quoted HTML attributes (
data-conf-name,data-location,aria-label, metacontent, map and share links), where a"in the data would end the attribute.Change
jsonify, the idiom_includes/head.htmland the JSON-LD block already use:index.html(calendar button),_layouts/conference.html(calendar links, follow-series state),_includes/calendar.js(calendar page).escape, orurl_encodewhere it is part of a URL (Google Maps queries, Twitter handles). The share links useurl_encode | replace: "+", "%20", becausemailto:reads+literally. Coversindex.html,_layouts/conference.html,_layouts/summary.html,_pages/series.html,_includes/action_bar.html,conference_detail_actions.html,index_conf_title_row.htmlandindex_conf_date_place.html(including theextra_placeslinks). URL fields stay as they are: the schema validates them asHttpUrl, which percent-encodes quotes.(extended)label:calendar.jsnever resetextended, so every conference after the first extended CfP was labelled "(extended)": 66 labels for 16 extended CfPs. It now resets in theelsebranch, ascalendar-deadlines.icsalready does.tests/test_template_escaping.pyscans every template. It fails when a free-text conference field (any schema field apart from year, dates, deadlines, timezone andsub, so later fields count too) reaches a script without a finaljsonify/slugify, when ajsonify'd value sits in quotes, or when free text inside an HTML tag has noescape/url_encode. It follows fields into include parameters (conf_name=conf.conference) and into variables set withassignorfor, which is how the action bar and theextra_placeslinks got past a direct check. Values passed throughcapture, or set in another file, still get past it; the module docstring says so.The data keeps its real spelling: apostrophes, quotes and backslashes in names and places are legitimate, so neither a data check nor an apostrophe-rewriting formatter fits.
Tests
main's templates at all 52 sites changed here (14 in scripts, 38 in attributes) and passes after. Fixture cases check the checker, including include parameters, loop variables andslugify'd assigns.pytest tests/: 2487 passed, 4 skipped, 3 xfailed, 2 xpassed.ruff 0.4.4,black 24.4.2,isort 5.13.2,docsig 0.53.2clean on the test file.bundle exec jekyll build --config _config.yml,_config.test.yml, then a Node syntax check of every inline script on all 197 built pages: 2 broken onmain, 0 now.PyCon Côte d'Ivoire "Quoted" & <b>, placeAbidjan, Côte d'Ivoire "Q" & \and an extra place with a": 0 broken scripts, and all 36 attributes carrying the name or place on the front, conference and series pages parse back to the original value. Map and share links come out fully percent-encoded.conferences.ymlwithcfp_ext.🤖 Generated with Claude Code
https://claude.ai/code/session_01YSanwpb5BXzbhLxMFyz9yS