Skip to content

plan: <tonk-portal> sandboxed artifact rendering#460

Open
Gozala wants to merge 2 commits into
stagingfrom
feat/sandbox-iframes
Open

plan: <tonk-portal> sandboxed artifact rendering#460
Gozala wants to merge 2 commits into
stagingfrom
feat/sandbox-iframes

Conversation

@Gozala
Copy link
Copy Markdown
Collaborator

@Gozala Gozala commented May 19, 2026

Rough plan of how sandboxed iframe could be manifested


PR-Codex overview

This PR introduces the <tonk-portal> element, which allows for the rendering of untrusted HTML artifacts in a secure manner using nested iframes. It outlines the structure, functionality, and lifecycle of the component, ensuring safe data access while isolating the host page.

Detailed summary

  • Added documentation for <tonk-portal> element.
  • Described the context and purpose of <tonk-portal>.
  • Explained the artifact rendering process using nested iframes.
  • Defined the source attribute as a DID for content claims.
  • Outlined the element's shape and attributes.
  • Detailed DOM state signaling and lifecycle events.
  • Explained frame topology and trust boundaries.
  • Described the bootstrap process and bridge handshake.
  • Defined wire shape for request/response handling.
  • Explained guest API surface and usage for artifact authors.
  • Outlined content-change strategy and data flows.
  • Discussed threat model and security measures.
  • Included details on implementation order and possible future enhancements.

✨ Ask PR-Codex anything about this PR by commenting with /codex {your question}

Design doc for a custom element that renders untrusted HTML
artifacts inside a nested-iframe sandbox. Outer iframe holds a
fixed bootstrap under sandbox="allow-scripts" with no
allow-same-origin; inner iframe inherits the outer's opaque
origin via srcdoc so the artifact's scripts can reach
parent.tonk synchronously. The outer constructs a MessageChannel
and posts port2 up to the host; subscriptions return transferred
ReadableStreams so the host keeps no subscription-lifecycle
state.
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 19, 2026

Wrangler output for this change:

⛅️ wrangler 4.64.0 (update available 4.93.0)
─────────────────────────────────────────────
[custom build] Running: nix build .#tonk-cloudflare-artifacts
[custom build] path "/home/runner/work/tonk/tonk/rust/tonk-access-service" does not contain a 'flake.nix', searching up
[custom build]
[custom build] warning: ignoring untrusted flake configuration setting 'extra-substituters'.
[custom build] Pass '--accept-flake-config' to trust it
[custom build] warning: ignoring untrusted flake configuration setting 'extra-trusted-public-keys'.
[custom build] Pass '--accept-flake-config' to trust it
[custom build]
🌀 Building list of assets...
✨ Read 591 files from the assets directory /home/runner/work/tonk/tonk/result/tonk-ui
🌀 Starting asset upload...
No updated asset files to upload. Proceeding with deployment...
Total Upload: 1088.83 KiB / gzip: 397.17 KiB
Worker Startup Time: 15 ms
Your Worker has access to the following bindings:
Binding Resource
env.BUCKET (tonk-spaces) R2 Bucket
env.ASSETS Assets
env.R2_ACCOUNT_ID ("5f20ca8a0de0a5ac52a14fa8bf9c90db") Environment Variable
env.R2_BUCKET_NAME ("tonk-spaces") Environment Variable

Uploaded tonk-access-service (3.32 sec)
Worker Version ID: 02ae8d09-240a-4d48-98d3-cc4f6725a12e
Version Preview URL: https://02ae8d09-tonk-access-service.tonk.workers.dev
Version Preview Alias URL: https://pr-460-tonk-access-service.tonk.workers.dev

To deploy this version to production traffic use the command wrangler versions deploy

Changes to non-versioned settings (config properties 'logpush' or 'tail_consumers') take effect after your next deployment using the command wrangler versions deploy

Changes to triggers (routes, custom domains, cron schedules, etc) must be applied with the command wrangler triggers deploy

@Gozala Gozala marked this pull request as ready for review May 20, 2026 07:35
jackddouglas added a commit that referenced this pull request May 21, 2026
The niri-strip view's embedded-script approach is a stopgap. The
destination architecture (PR #460) has <tonk-display> as a pure
declarative {field}-substitution template and routes arbitrary
HTML+CSS+JS through <tonk-portal> — a sandboxed nested-iframe
element with parent.tonk.{query,subscribe,transact} as the data
surface.

Three pieces of plumbing exist only to keep the stopgap working:
<tonk-display>'s script-activation pass, the <script>/<style>
carve-out in tonk-concept's binding walker, and the outer
<template> wrapper around the niri view body. plan/
niri-portal-migration.md records the rollback for when portals
land:

- Move the niri view body to an artifact-content claim
- Swap <tonk-display view=niri-strip> for <tonk-portal source=...>
- Replace the hidden <tonk-concept> + MutationObserver hack with
  parent.tonk.subscribe(...) reading a real ReadableStream
- Replace tonk-layout/* CustomEvents with
  parent.tonk.transact(notation) (or PR #461 transients)
- Delete <tonk-display>'s script-activation helper
- Optionally remove the binding-walker carve-out

Adds a doc-comment header on tonk-ui::niri pointing at the plan.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant