feat(ui): WebUI modernization PR6 — streaming-safe markdown tokenizer, golden tests, strict CSP#114
Closed
jkyberneees wants to merge 1 commit into
Closed
Conversation
…, golden tests, strict CSP - Replace the regex-pipeline markdownToHtml with a hand-written line-based block parser + inline tokenizer. Unterminated fenced code blocks render their collected lines as a code block (EOF = fence close); unterminated inline constructs (**, backtick, ~~) render literally, so partial markdown no longer flashes broken markup while streaming. DOM contract preserved (h1-h4, hr, code-block/cb-header/ cb-lang/cb-copy, ul/ol, p/br); .cb-copy is now a <button> (delegated clicks in render.js) with a UA-style reset in style.css. - Extract escapeHtml/escapeAttr into leaf js/escape.js (re-exported by utils.js) so markdown.js is testable under Node without a DOM. - Golden tests in js/markdown.test.js (node:test, 26 tests) covering every block/span type, streaming edge cases, link scheme allowlist, and HTML escaping; new ui-js CI job. - Strict Content-Security-Policy on static responses (script-src 'self', no inline scripts); frame-ancestors folded into the CSP.
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
odek | a712b3d | Commit Preview URL Branch Preview URL |
Jul 26 2026, 01:29 PM |
Contributor
Author
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.
Summary
Sixth PR of the WebUI modernization roadmap — Phase 3b: streaming-safe markdown + golden tests + strict CSP. Stacked on #113 (
feat/webui-modernization-5).Streaming-safe markdown tokenizer (
ui/js/markdown.js)The old regex pipeline broke visibly while a response streamed — an unterminated
**or```rendered raw garbage until closed. The rewrite is a line-based block parser (code-fence state machine first, then headers/hr/lists/paragraphs) feeding a left-to-right inline span tokenizer, with asymmetric termination rules:**bold,`code`,~~strike~~) → render literallycode-block/cb-header/cb-lang/cb-copy,h1–h4,ul/ol,p), links keep the exact scheme allowlist (http/https/mailto/relative;javascript:/data:/vbscript:neutralized) andtarget="_blank" rel="noopener noreferrer", and*italic*still doesn't trigger inside words (a*b*c)Golden tests (
ui/js/markdown.test.js, CI)node --testrunner: every block type, inline spans, scheme allowlist (incl. paren-in-URL edge),<script>escaping, unterminated fence/bold/code/strike, and a golden multi-feature document.ui-jsjob intest.yml(setup-node,node --test "cmd/odek/ui/js/**/*.test.js"); run instructions added todocs/DEVELOPMENT.md.escape.jsextracted as a leaf module so the tokenizer is testable under Node without DOM/localStorage side effects (utils.jsre-exports).Strict CSP (
serve.go)Now that every inline event handler was eliminated in PR5,
script-src 'self'is possible. The static handler sets the full policy:default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self'; connect-src 'self' ws: wss:; frame-ancestors 'none'; base-uri 'none'; form-action 'none'(style-src 'unsafe-inline'only for the fewstyle="display:none"attributes). This closes the residual XSS surface that markup sanitization alone couldn't reach.X-Frame-Options: DENYstays for legacy browsers.Verification
node --test: 26 pass, 0 fail ✅;node --checkall 13 UI JS files ✅go build,go vet, fullcmd/odeksuite ✅ (existing CSP header test still passes)/and/app.js✅**bold→ literal; unterminated fence → open code block ✅