A Chrome extension (Manifest V3) that adds a Preview HTML button next to
.html / .htm attachments in GitHub Pull Request and Issue comments. Clicking
it fetches the attachment using your existing GitHub session and renders it in a
sandboxed, isolated preview tab — no download-and-open round trip.
Built for reviewers of internal/private repositories who receive diff-explanation HTML attached to PR comments.
content script background worker preview page (privileged) sandbox iframe
───────────── ──────────────── ───────────────────────── ──────────────
detect .html link ──▶ fetch(url, credentials)
add "Preview HTML" validate (status/size/type)
button store HTML in
on click, send URL ──▶ chrome.storage.session
open preview.html?id=… ──▶ read stored HTML
show metadata
postMessage(html) ─────────────▶ document.write(html)
(scripts run, isolated)
The content script never fetches or renders the attachment, so untrusted HTML
never touches the GitHub page's DOM or origin. See DEVNOTES.md for the
security model and the answers to the spec's pre-implementation questions.
pnpm installpnpm build— outputs the unpacked extension todist/.- Open
chrome://extensions, enable Developer mode (top right). - Click Load unpacked and select the
dist/folder. - Re-run
pnpm buildafter code changes, then click the reload icon on the extension card.
- Open a GitHub PR or Issue that has a
.html/.htmfile attached to a comment. - A small Preview HTML button appears next to the attachment link.
- Click it. A new tab opens showing the file's metadata (filename, source URL, fetch time) and the rendered HTML inside an isolated sandbox.
| Command | Purpose |
|---|---|
pnpm dev |
Vite dev server with HMR (CRXJS). |
pnpm build |
Production build to dist/. |
pnpm typecheck |
tsc --noEmit. |
pnpm test |
Unit tests (Vitest). |
pnpm check |
typecheck + test + build. |
manifest.json # MV3 manifest (CRXJS rewrites the src/* paths on build)
vite.config.ts # CRXJS plugin + explicit inputs for preview/sandbox pages
src/
content.ts # detect links, add buttons, observe DOM, forward clicks
background.ts # fetch + validate + store + open preview tab
preview.html / .ts # privileged page: metadata + broker to sandbox
sandbox.html / .ts # sandboxed renderer (scripts run, fully isolated)
shared/ # config, detect, validate, messages, storage, format
test/ # unit tests for detect + validate
examples/sample.html # manual-test fixture (inline script, alert, ext. image)
- Build and load unpacked (above).
- Open a PR/Issue in a private repo you have access to.
- Attach
examples/sample.html(or any.html) to a comment via drag & drop. - Confirm a Preview HTML button appears next to the link.
- Click it; confirm the preview tab opens and renders the HTML.
- With
examples/sample.html, confirm:- the inline-script status line shows "ran inside the isolated sandbox" (scripts execute), and
- no
alert()dialog appears (modals suppressed), and - the external image fails to load (network blocked).
- Try a file larger than 5 MB; confirm a clear "too large" error.
- Confirm
.txt/.pdfattachments get no button. - Sign out of GitHub (or use a repo you lack access to); confirm a clear "Not authorized" error instead of a silent failure.
- Attachment HTML is rendered only inside a Manifest V3 sandbox page
(
src/sandbox.html): opaque origin (noallow-same-origin), so it cannot read GitHub cookies/localStorage or call extension APIs. - Sandbox CSP blocks all network (
default-src 'none',connect-src 'none') and external/eval scripts; only inline scripts run.alert/confirmare suppressed (noallow-modals); popups and forms are disabled. - HTML is stored in
chrome.storage.sessiononly (cleared when the browser closes); never written to disk. - Fetches are limited to GitHub hosts; the response is size-capped (5 MB) and rejected if clearly binary.
- Permissions are minimal:
storage,tabs, and GitHub host access only.
- Detection depends on GitHub's attachment URL shape and DOM. If GitHub changes these, links may stop being detected.
- External CSS, images, fonts, and scripts in the attachment are blocked by the sandbox CSP (no network). Self-contained HTML previews best.
- Scripts requiring
eval/new Functionwill not run ('unsafe-eval'is off). - GitHub Enterprise Server is out of scope. To enable it, add the GHE host to
ALLOWED_HOST_SUFFIXES(src/shared/config.ts) and tohost_permissions/ content-scriptmatchesinmanifest.json. - Firefox is out of scope.
- Previews are not persisted: re-opening a preview tab after the browser session ends requires clicking Preview HTML again.
- Configurable allow-list UI for GitHub Enterprise hosts.
- Optional opt-in toggle to allow external resources (relaxed CSP) per preview.
- Firefox / cross-browser packaging.
- Chrome Web Store packaging and icons.