fix(canvas): follow live on design revisions; execute react artifacts in a sandboxed frame - #814
Merged
Conversation
A design revision acts on the live Canvas, but a replay cursor parked by jump-from-chat kept the up-to-cursor simulator window from ever including the incoming revision events - the Canvas looked stale until the session was reopened. Snap back to follow mode on submit so the revision streams and materializes in view. Pre-commit hook ran. Total eslint: 18, total circular: 0
…frame React canvases could not run under the packaged CSP (no unsafe-eval, and srcdoc frames inherit the parent policy), so the desktop showed a notice card instead of the artifact. Serve the compiled artifact document over a dedicated canvas-artifact:// URI scheme instead: its response carries its own CSP, the iframe is a separate origin sandboxed with allow-scripts only, and the app CSP merely allows the scheme in frame-src. - reactArtifactDocument.ts ports the cloud viewer's sandbox document (sucrase compile, React 18 UMD runtimes, error overlay, strict CSP) so desktop and public share links run identical artifact semantics - Rust CanvasArtifactStore (16 entries / 8 MiB, oldest evicts) behind a canvas_artifact_publish command and the protocol handler (CSP + nosniff + no-store headers, 404 for unknown ids) - ReactArtifactRunner publishes once per source hash and renders the frame; compile and publish failures surface in a visible alert - react-live removed; IPC unreachable from artifacts (no remote capability grants, opaque-origin rejection, connect-src 'none') Pre-commit hook ran. Total eslint: 18, total circular: 0
Pre-commit hook ran. Total eslint: 18, total circular: 0
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.
Problem
Two follow-ups from the Canvas audit (PRs #709/#767/#768):
Stale Simulator after a design revision. A design revision acts on the live Canvas, but when the replay cursor had been parked by jump-from-chat (
navigateToEvent), the up-to-cursor simulator event window excluded the incoming revision events. The Canvas looked stale until the session was reopened — verified on a real machine: the revision completed, the activity row showed the steps, yet the visible canvas kept the pre-revision content.React canvases could not execute on desktop. The packaged CSP (
script-src 'self' 'wasm-unsafe-eval') blocks react-live'snew Function, and srcdoc iframes inherit the parent policy, so an inline-script srcdoc runtime cannot run either. After the audit fix the desktop showed a visible notice card instead of a silent blank — but the artifact still never ran.Solution
CanvasDesignSurfacesnaps back to follow mode (goLiveAtom) when a design revision is submitted, so the revision streams and materializes in view.Serve compiled react artifacts over a dedicated
canvas-artifact://URI scheme instead of host-document eval:reactArtifactDocument.tsports the cloud viewer's sandbox document (sucrase compile, React 18 UMD runtimes, error overlay, strict CSP withconnect-src 'none'), so desktop and public share links run identical artifact semantics.CanvasArtifactStore(16 entries / 8 MiB, oldest evicts) behind acanvas_artifact_publishcommand; the protocol handler responds with its own CSP + nosniff + no-store headers, 404 for unknown ids.ReactArtifactRunnerpublishes once per source hash and renders<iframe sandbox="allow-scripts" src="…canvas-artifact.localhost/<id>">; compile/publish failures surface in a visible alert. react-live removed.frame-src;unsafe-evalstays out.Security
The artifact frame is a separate, sandboxed, opaque origin. WebView2 does inject
__TAURI_INTERNALS__into subframes (wry injects init scripts for all frames), but IPC is unreachable through three independent layers, each verified: no capability grants any remote context; the IPC protocol rejects the opaque frame'sOrigin: null; and the artifact document'sconnect-src 'none'blocks the invoke transport outright. Live test from inside a real artifact frame:invoke()never completes (blocked at transport).sandboxmust never gainallow-same-origin— pinned by tests.Verification
tsc --noEmitclean; canvas + CanvasInlineCard suites 19 files / 159 tests green (includes newreactArtifactDocument.test.ts, rewritten runner tests, and a regression test that a parked replay cursor snaps to follow on submit).cargo check -p org2clean; store/protocol unit tests compile (the test exe cannot load on the dev machine due to a pre-existing comctl32 manifest issue; they should run on CI).http://canvas-artifact.localhost/ra-…withsandbox="allow-scripts"; the button inside was clicked and cycled state (Rose → Amber) proving interactivity; the revised html canvas from the previous session renders its materialized state after restart.Notes