unsloth/studio/frontend
Daniel Han 5171bcc991 Studio: serve HTML preview from a same-origin route so inline scripts run
Closes the long-documented follow-up. Inline <script> and onclick handlers
inside the assistant's ```html fence were dead under the previous srcdoc
path because Chromium inherits the embedder CSP (script-src 'self') for
srcdoc / data: / blob: iframes per HTML / CSP3. The only browser-supported
escape is a same-origin URL whose response headers carry an overriding CSP.

Backend: new POST /api/preview/html stashes the source for 10 min behind a
192-bit random token; GET /api/preview/html/{id} serves the snippet with
default-src 'none' + script-src 'unsafe-inline' + frame-ancestors 'self' +
X-Frame-Options SAMEORIGIN so the host chat page can iframe it but third
parties cannot. The GET is intentionally unauthenticated because browsers
do not attach Authorization to iframe subresource loads -- the unguessable
URL token is the authorisation. Eviction caps the in-memory store at 256
entries per worker; TTL sweep runs on each access.

Frontend: HtmlPreview now POSTs the source on mount, holds about:blank
until the URL arrives, then sets iframe src to the returned path. The
iframe sandbox stays "allow-scripts allow-modals allow-popups" with NO
allow-same-origin / allow-top-navigation, so even though the URL is
same-origin the iframe document is treated as a unique opaque origin
(cannot reach parent storage / DOM, cannot navigate the host page).
A srcdoc fallback kicks in if the POST fails so the layout still renders.

Tests:
* 9 new backend cases pin auth gating on POST, the unauth GET path,
  CSP shape, X-Frame-Options override, TTL expiry, oldest-first eviction,
  and per-call token uniqueness.
* Frontend vitest mocks the fetch round-trip; two existing tests rewritten
  to await data-preview-state=ready, plus a new failing-fetch case that
  exercises the srcdoc fallback (so a future regression there is loud).

Updates the in-host-CSP comment in main.py to reflect that the
"same-origin backend route" follow-up is now landed.
2026-05-25 14:00:06 +00:00
..
public Polish/cloud to providers (#5450) 2026-05-15 19:29:21 +04:00
src Studio: serve HTML preview from a same-origin route so inline scripts run 2026-05-25 14:00:06 +00:00
.gitignore perf(studio): upgrade to Vite 8 + auto-install bun for faster frontend builds (#4522) 2026-03-25 04:27:41 -07:00
.gitkeep add studio root folder 2026-02-02 09:14:35 +00:00
.install-script-allowlist Studio: harden install-script gate against PR self-allowlist 2026-05-24 16:04:31 +00:00
.npmrc security: NOT affected by Mini Shai-Hulud (May-12 wave) -- forward-looking hardening only (#5397) 2026-05-13 04:58:12 -07:00
biome.json feat: add seed dataset support with configuration, preview, and builder utilities 2026-02-14 18:44:38 +01:00
components.json add studio root folder 2026-02-02 09:14:35 +00:00
data-designer.openapi (1).yaml save and import, and fixes 2026-02-04 14:32:49 +01:00
eslint.config.js Final cleanup 2026-03-12 18:28:04 +00:00
index.html Final cleanup 2026-03-12 18:28:04 +00:00
package-lock.json Studio: render HTML and SVG fences inline with sandboxed preview tabs 2026-05-23 14:00:36 +00:00
package.json Studio: render HTML and SVG fences inline with sandboxed preview tabs 2026-05-23 14:00:36 +00:00
tsconfig.app.json Relax frontend unused local check (#4388) 2026-03-17 16:04:11 -07:00
tsconfig.json cleanup 2026-02-04 13:28:39 +01:00
tsconfig.node.json cleanup 2026-02-04 13:28:39 +01:00
vite.config.ts Fix Install commands for Windows + 1 line installs (#4447) 2026-03-19 02:09:09 -07:00
vitest.config.ts Studio: render HTML and SVG fences inline with sandboxed preview tabs 2026-05-23 14:00:36 +00:00