Skip to content

feat: render assistant answers through a sanitized markdown allowlist - #557

Merged
caitlon merged 4 commits into
devfrom
feat/assistant-markdown-render
Oct 9, 2026
Merged

caitlon merged 4 commits into
devfrom
feat/assistant-markdown-render

Conversation

@caitlon

@caitlon caitlon commented Oct 9, 2026 •

Copy link
Copy Markdown
Owner

Problem

An assistant answer can carry text the model copied from project data, such as a project name or an expert's position, so whatever renders it must not turn that text into an image, a link to another address, or raw HTML.

Change

Adds react-markdown pinned at 10.1.0 and AssistantMarkdown, which renders an answer from the elements p, strong, em, ul, ol, li, code and br only. unwrapDisallowed keeps the text of anything else, so a markdown link, an autolink or a heading shows as plain text and an image renders nothing; skipHtml drops raw HTML. A [n] marker in the text of a paragraph, list item, bold or italic run stays plain text while the caller passes no source list (an answer still streaming has none yet); once a list is passed, the marker becomes an in-page anchor #assistant-src-<messageId>-<n> when the answer has source n, and its click calls onCite(n) instead of changing the location; a marker with no such source is struck through and is not a link, and its digits are shown as written. Markers inside inline code stay literal. The overrides are module-level components that read the citation data from a context, so a re-render or a streamed token does not remount the answer and a clicked citation keeps focus. isAllowedAssistantUrl accepts only a string that starts with https:// and parses as an https: URL; the source list in the next PR uses it. Nothing renders the component yet: the panel wires it in later.

Verification

New tests in AssistantMarkdown.test.tsx and url-allowlist.test.ts cover the allowed formatting, links, autolinks and headings coming out as text, javascript: links, hard line breaks, images (no element and no alt text), raw HTML, no leaked node attribute, a [n] with no source list, a known and an unknown [n] (including a number too large for a safe integer), a click that is default-prevented and leaves location.hash unchanged, citations inside nested emphasis and inside code, the anchor and paragraph DOM nodes surviving a re-render with a new source list and handler, and the paragraph node surviving appended content. npm run lint, npm run typecheck, npm run test:coverage and ./scripts/ci/ci-local.sh fast are green.

Migrations

None.

Screenshots

None, nothing renders the component yet.

@caitlon caitlon added this to the v1.1-polish milestone Oct 9, 2026
@caitlon caitlon added type:feature New functionality area:frontend React frontend labels Oct 9, 2026
@caitlon caitlon self-assigned this Oct 9, 2026
@greptile-apps

greptile-apps Bot commented Oct 9, 2026

Copy link
Copy Markdown

Automatic reviews are disabled for this repository.

@github-actions github-actions Bot added the size:M 300 to 600 changed lines. The target size. label Oct 9, 2026
@sonarqubecloud

sonarqubecloud Bot commented Oct 9, 2026

Copy link
Copy Markdown

@caitlon
caitlon merged commit 8d8fa28 into dev Oct 9, 2026
20 checks passed
@caitlon
caitlon deleted the feat/assistant-markdown-render branch October 9, 2026 22:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:frontend React frontend size:M 300 to 600 changed lines. The target size. type:feature New functionality

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant