feat(file-preview): render local HTML files as sandboxed pages

Clicking an agent's `.html` path showed source text or downloaded it, so a
generated report could only be viewed by asking the agent to start a web
server. Render it instead, without serving HTML same-origin:

- POST /api/sessions/:id/html-view mints a capability for the file's own
  directory (workspace path, or outside it under the attachment guard).
- GET /html-view/:cap/* serves the page and its relative assets with
  `Content-Security-Policy: sandbox` WITHOUT allow-same-origin, so the page
  runs in an opaque origin (also as a top-level tab) and cannot read the
  Codeman document, its cookies or its API.
- Served files: non-dot, asset-allowlisted, realpath-confined to that
  directory, blocklist applied; GET only. Capabilities are memory-only with a
  rolling TTL and are revoked with the web-tab ones on logout.
- Frontend: the file preview renders HTML in a sandboxed iframe (popout opens
  the same URL); terminal `.html` links go to the preview, not the log viewer.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
stefaan van hoofandClaude Opus 5.5 committed 2026-10-07 16:26:39 +02:00
1 parent ffaa5ee80c
commit fe77b5238e
11 files changed
+462 -2

No files matched your search

+2
View File
@@ -178,6 +178,7 @@ import {
registerTeamRoutes,
registerMuxRoutes,
registerFileRoutes,
registerHtmlViewRoutes,
registerScheduledRoutes,
registerHookEventRoutes,
registerApprovalRoutes,
@@ -1116,6 +1117,7 @@ export class WebServer extends EventEmitter {
registerTeamRoutes(this.app, ctx);
registerMuxRoutes(this.app, ctx);
registerFileRoutes(this.app, ctx);
registerHtmlViewRoutes(this.app, ctx);
registerScheduledRoutes(this.app, ctx);
registerHookEventRoutes(this.app, ctx);
registerApprovalRoutes(this.app, ctx);