Skip to content

Add authenticated shared web UI - #319

Open
Gratenes wants to merge 20 commits into
zeronsh:mainfrom
Gratenes:wip/browser-remote-parity
Open

Gratenes wants to merge 20 commits into
zeronsh:mainfrom
Gratenes:wip/browser-remote-parity

Conversation

@Gratenes

@Gratenes Gratenes commented Sep 11, 2026

Copy link
Copy Markdown

Summary

Adds an authenticated browser build of the shared GPUI interface. The browser renders the shared Shell/application state and connects to a native Zeron device through the existing RPC protocol and DeviceRoom relay. Execution stays on the native host; the browser does not run an engine or use loopback IPC.

Included

  • WASM entry point for the shared UI, with browser support for chat, terminal, files/Git, queues, attachments, HTTP previews and theme import.
  • WorkOS-backed browser sessions, owner-scoped device discovery, logout and revocation.
  • Epoch-guarded connection lifecycle and no automatic mutation replay.
  • Upload backpressure that permits relay-safe frames above the browser buffer high-water mark while continuing to deliver incoming RPC messages. Attachments are chunked: the attachment limit is 24 MiB; the encoded relay-frame ceiling is 1 MiB.
  • Exact published GPUI runtime dependency, locked build instructions, local serving headers and focused web CI.

Merge-readiness sweep

  • Reconciled upstream 7655c662c2e0e1dea91a9c4d9929725e219abd82, resolved the root lock conflict and reviewed the preview/sidebar auto-merges.
  • Updated the independent web and lifecycle lockfiles for upstream version 0.2.61.
  • Replaced sibling runtime paths with published Gratenes/zui@c1700b8de27a07b5bc1a190440b64e7323c008f9, including the input/runtime fixes from Fix browser runtime wakes, fonts, touch and text input zui#8.

Validation

  • Clean-checkout trunk build --release --locked: passed, using nightly-2026-09-08, Trunk 0.21.14 and the published runtime pin; no local Cargo source override.
  • 14 browser lifecycle/transport tests passed, including consecutive upload chunks, buffer draining, inbound progress, cancellation and no replay.
  • Edge typecheck and 67 tests passed after npm ci in the clean checkout (44 unit + 23 workerd).
  • Native cargo check --locked -p zeron: passed after reconciliation, using locally supplied Linux development libraries.
  • 18 preview tests passed; one existing environment-dependent coordinator test remains ignored.
  • The focused native attachment chunk-boundary test passed.

Commands/configuration: apps/web/README.md.
Hosted checks: Web validation workflow.

Manual coverage and limits

The author has verified phone taps, scrolling, keyboard behavior and popovers; phone copy/paste and emoji testing remains pending. Device/browser versions and the tested revision were not recorded.

Earlier development checks reported real WorkOS login, device selection, chat, terminal commands, file editing, Git diffs, queue operations, previews and theme persistence. Those reports are not a reproducible end-to-end suite for this final commit; this sweep does not claim to repeat those authenticated flows.

Remote project preview is HTTP-only: WebSocket upgrades and Vite HMR are not supported. Full desktop/browser parity, one-command deployment and direct/self-hosted transport are outside this change; SELF_HOSTING_ROADMAP.md remains a proposal.

Before merge

  • Record the author's phone copy/paste and emoji result; keep draft until then.
  • Obtain passing hosted checks and maintainer review.
  • Merge zui Use native word-editing shortcuts on every platform #8 first; repin the web manifest/lockfile to its published upstream revision and rerun the locked build before merging this PR.

View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.

Proof-of-work snapshot: WorkOS browser sessions, DeviceRoom RPC, shared UI parity and friendly device names. Pins published GPUI runtime fixes. Excludes local credentials, generated artifacts and experimental apps. Locked WASM build and scoped tests passed; exact native build remains unverified after validation timeouts. Not PR-ready.
@Gratenes Gratenes changed the title Add web UI support Add authenticated shared web UI Sep 12, 2026
@Gratenes

Copy link
Copy Markdown
Author

Pushed 08fcd03: production deployment preparation and multiuser authentication. Keeping this PR in draft. Known unresolved issue from manual phone testing: emojis do not render correctly in chat messages or when pasted into the input. This is a rendering failure, not a passed emoji check; root cause has not yet been investigated. Previously verified taps, scrolling, keyboard behavior and popovers remain recorded separately.

@Gratenes
Gratenes marked this pull request as ready for review September 13, 2026 07:12
@Gratenes

Copy link
Copy Markdown
Author

Updated to 5c0a81b and marked ready for review.

The emoji issue mentioned in my earlier comment is fixed in staging. I’ve also manually verified terminal input/focus, mobile drawers, reconnect behavior and the mobile tap-highlight fix.

This update resolves the upstream conflicts and pins the published runtime fixes, so the web build no longer depends on local runtime overrides.

Local validation passed: locked release WASM build, 21 lifecycle tests, 44 unit tests, 24 workerd tests and 39 production-routing checks. The workerd runner assertions were investigated and addressed; repeated runs are now clean. Desktop/mobile browser startup checks also passed.

Please land zui #8 first; I’ll then repin to its upstream revision. Hosted CI still needs confirmation. Production has not been deployed, and the WorkOS/storage rollout checklist remains a pre-merge requirement.

@wingleeio wingleeio left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the thorough work here — the design is sound and the security posture (PKCE + state/nonce, __Host- cookies, CSRF header + Origin checks, sealed provider tokens, owner-scoped sessions, browser forced to role=client, catalog-only preview relay) is careful. I audited the vendored crate, the forked git dependency, CI/deploy changes, the postinstall hook, and the edge auth code, and found nothing unsafe. Findings below, ordered by importance.

Blocking / should fix before merge

  1. Pin mismatch between description, README, and manifest. The PR body says zui is pinned at c1700b8d…, apps/web/README.md and docs/web-deployment-session-summary.md say aca6b042…, and apps/web/Cargo.toml / Cargo.lock actually pin 8d78b9c2…. Per your own checklist, zui #8 should land first and this should be repinned to a zeronsh/zui rev, with the [patch."https://github.com/zeronsh/zui"] block removed. As written, deploy.yml builds production web.zeron.sh assets from a personal fork.

  2. Per-frame authorization round-trip to a single global DO (edge/src/device-room.ts webSocketMessagebrowserSessionActivevalidateBrowserSession). Every relayed frame in both directions for a browser client does a sub-request to the one browser-sessions-v1 BrowserSessionStore instance, with refresh: true by default (so a frame path can trigger a WorkOS refresh). Terminal output is many frames/sec per client; this makes one DO a global throughput ceiling and adds latency to every frame. There's also a correctness concern: webSocketMessage is now async and awaits a non-storage sub-request, so workerd can deliver the next message before the previous one finishes validating — frames on a stream could be relayed out of order. The alarm-based recheck (BROWSER_SESSION_RECHECK_MS) plus the /browser-revoke push already cover revocation; I'd drop the per-frame check or make it a local, time-bounded cache on the socket attachment.

  3. Contributor-specific infra committed to the repo. edge/wrangler.staging.jsonc hardcodes a personal Cloudflare account_id, the zeron-test.embedez.com custom domain, and a separate WorkOS client id; docs/web-deployment-session-summary.md is a session log of that staging deploy. Either template the staging config or drop it and the session summary.

  4. /auth/browser/* broker API is dead code for this PR. edge/src/browser-auth.ts exposes exchange/refresh/revoke returning raw provider access+refresh tokens to any holder of BROWSER_BROKER_TOKEN. Nothing in the browser flow uses it, BROWSER_BROKER_TOKEN isn't in Env or wrangler config, and its only consumer is the "not implemented" SELF_HOSTING_ROADMAP.md. It's fail-closed (501) when unset, but it's a new credential-issuing surface plus a === timing-unsafe token compare. Suggest removing it (and the roadmap doc) from this PR and landing it with the self-hosting work.

Should fix

  1. forward() in edge/src/index.ts doesn't strip the new internal headers. It clears ROOM_KIND_HEADER for exactly this reason but passes through x-comet-browser-session-hash, x-comet-browser-room, and x-comet-browser-session-store from native bearer clients. DeviceRoom re-validates the hash and matches owner so I couldn't find an escalation, but the /browser-revoke route's only gate is that store header. Add the three to the delete list for defense in depth.

  2. Host device name is now sent to and stored on the edge (crates/engine/src/lib.rs .with_device_name(local_device_name(...))&name=browser_devices.name). That's the machine hostname by default. Worth a note in the description and probably an opt-out, since it's a new piece of PII in DO storage.

  3. postinstall patching node_modules (edge/scripts/patch-vitest-pool.mjs) will break npm ci on any @cloudflare/vitest-pool-workers bump. Prefer patch-package / npm overrides, or upstream the fix and drop the hook.

Scope

  1. This PR bundles at least six independently reviewable changes: the RpcClient writer/shutdown refactor (affects native too — ServerFrame now rejects envelopes without exactly one of ok/item/err/done; I checked server.rs and it's compatible), large UI module splits (composer/input.rs, */presentation.rs — confirmed these are essentially moves), the alacritty vendoring (verified byte-identical to crates.io 0.26.0 apart from wasm cfg gating), the zeron-rpc/zeron-syntax feature-gating, the web app, and the edge BFF + deploy changes. Splitting the native-affecting refactors out first would make the remaining browser work much easier to review and bisect.

Nits

  • dtolnay/rust-toolchain@master in both workflows; the repo otherwise uses @stable.
  • browser-sessions.ts swallows ALTER TABLE errors with bare catch {} on every DO construction — a migration table would be clearer than try/catch schema evolution.
  • web-validation.yml and deploy.yml duplicate the ~40-line WASM build/check block; a composite action would keep them in sync.

@Gratenes

Copy link
Copy Markdown
Author

Good morning — here is my attempt to un-slop this PR and address the review properly.

  1. The documentation now consistently identifies the current Gratenes/zui checkpoint. The final zeronsh/zui repin and removal of the temporary fork patch are intentionally waiting for zui Use native word-editing shortcuts on every platform #8 to land, so we can use its actual upstream merge SHA.

  2. Removed per-frame BrowserSessionStore validation from DeviceRoom.webSocketMessage. Frame relay is synchronous again, avoiding the global per-frame Durable Object round-trip, refresh work and possible message reordering. Alarm-based rechecks and /browser-revoke push revocation remain in place.

  3. Removed the contributor-specific staging Wrangler configuration, staging deployment document and deployment-session log. The read-only post-deployment check is now named production-smoke.mjs.

  4. Removed the unused /auth/browser/* token broker, its tests, route and BROWSER_BROKER_TOKEN documentation. The speculative self-hosting roadmap that depended on it was also removed.

  5. Added centralized forwarding-header sanitization. Caller-supplied room-kind and browser-session trust headers are stripped before verified Worker-controlled values are applied. Regression coverage was added for spoofed headers and authorized workspace forwarding.

  6. Documented that published device names may derive from the machine hostname and documented ZERON_DEVICE_NAME as the privacy-preserving override.

  7. Migrated from @cloudflare/vitest-pool-workers to the supported @cloudflare/vitest-plugin. Replaced the handwritten node_modules mutation script with a version-pinned patch-package patch.

  8. Reduced the scope by removing the staging, broker and speculative roadmap work. I have not rewritten the existing published history. If splitting the remaining native-affecting work is still required, I can handle that separately.

I also changed the Rust setup actions to use the stable action tag and replaced exception-driven SQL column migrations with explicit schema inspection.

The final upstream zui repin remains required after zui #8 merges. The PR also currently conflicts with upstream main; I’ll resolve and recheck that before merge.

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.

2 participants