Repository navigation
fix(ui): harden markdown rendering - #92
Merged
Merged
Conversation
- Pin the `markdown` dependency to a patched build ([patch.crates-io], freenet/markdown-rs at a fixed rev), which also parses long documents in linear rather than quadratic time. - Render page content and the editor preview through one bounded path that shows text past its limits (size, nesting per line, block length, table size, reference count and expansion, HTML size) as escaped plain text. - Walk and drop markdown trees without recursion. Claude-Session: https://claude.ai/code/session_013fuenPkF3T7ZkeypDFSRmx
- Skip only a single leading byte order mark when measuring, as the parser does; any other U+FEFF counts as ordinary text. - Add a whole-document limit on block container markers, alongside the per-line one. - Check the page size before resolving [[page links]], cap the resolved output and the work spent on it, stop scanning at the last closing bracket pair, and look titles up through an index. - Make the limits a struct so tests reach each one with tiny inputs, and assert the counters against them: exact boundaries, linear scaling, the exact reference count and its half-limit gate, both HTML caps. - Run the parser regression inputs through the syntax-tree path too, test that the page view and editor preview render through the bounded module, and pin the patched markdown build in Cargo.lock. [AI-assisted - Claude] Claude-Session: https://claude.ai/code/session_013fuenPkF3T7ZkeypDFSRmx
[AI-assisted - Claude] Claude-Session: https://claude.ai/code/session_013fuenPkF3T7ZkeypDFSRmx
[AI-assisted - Claude] Claude-Session: https://claude.ai/code/session_013fuenPkF3T7ZkeypDFSRmx
…ike the parser - Estimate the containers that may be open on each line (markers plus indentation, carried through blank and lazy lines) and limit both the deepest line and the sum over all lines. - End a footnote label at its first unescaped `]`. - Show the plain-text fallback as one pre-wrapped text block instead of an element per line. - Keep the last page render and reuse it while its inputs are unchanged. [AI-assisted - Claude] Claude-Session: https://claude.ai/code/session_013fuenPkF3T7ZkeypDFSRmx
[AI-assisted - Claude] Claude-Session: https://claude.ai/code/session_013fuenPkF3T7ZkeypDFSRmx
Inside code and HTML blocks the parser's time grows with the square of a run of empty lines, so charge each run its length squared. [AI-assisted - Claude] Claude-Session: https://claude.ai/code/session_013fuenPkF3T7ZkeypDFSRmx
sanity
force-pushed
the
fix/harden-markdown
branch
from
October 1, 2026 03:03
96de75c to
c9e3ec8
Compare
Contributor
Author
Consolidated reviewTier: Full (renders content written by other people; availability-sensitive). Lenses runRound 1, at
Round 2, at
Findings and resolutionRound 1, four blocking findings, all fixed:
Round 2, security lens:
Round 2, testing lens (no blocking findings):
Verification
[AI-assisted - Claude] |
sanity
added a commit
that referenced
this pull request
Oct 1, 2026
Published from main at 258b192 (#92). [AI-assisted - Claude] Claude-Session: https://claude.ai/code/session_013fuenPkF3T7ZkeypDFSRmx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Page content is written by other people and rendered as markdown in the page view and the editor preview. The renderer should cope with malformed or unusually large input without stalling or failing.
Approach
markdownbuild.[patch.crates-io]pins freenet/markdown-rs branchfreenet/panic-fixesatc0646ed: the parser fixes River already uses (4dcf957), plus one commit that indexes the parser's edit map so that block-level parsing is linear rather than quadratic in document length. That commit was checked against the crate's test suite and by a differential run of generated inputs (identicalto_htmlandto_mdastoutput before and after).ui/src/components/markdown_render.rs), used by both the page view and the editor preview. Text past any limit is shown as escaped plain text, with line breaks kept. It is the only module that calls themarkdowncrate.[[page links]]are resolved; resolving stops at the last closing]], its output and work are capped, and title lookups go through an index.Limits
Calibrated against the real markdown files over 2 KiB across the Freenet and mediator repos (about 1,000 files).
]:count times]countA leading byte order mark is skipped when measuring, as the parser skips it; any other one counts as text. Footnote labels are read the way the parser reads them.
The plain-text fallback is one pre-wrapped text block rather than an element per line, and the page view reuses its last render while the content, page titles and link settings are unchanged, so re-renders triggered by unrelated updates do not repeat the work.
The slowest inputs found within the limits render in about 0.25 s natively (release build).
UI-only change:
markdownis a dependency ofdelta-uialone, so the site contract and delegate WASM are unchanged. Nothing needs migrating.Testing
cargo test -p delta-ui --bins -- markdown_render page_links:markdowncrate.Cargo.lockis checked to pin the patched build: the last fork commit changes no output, so this pin is what keeps it.The full workspace suite, clippy and the wasm check are clean locally.
[AI-assisted - Claude]
https://claude.ai/code/session_013fuenPkF3T7ZkeypDFSRmx