Add protected Cloudflare Quick Tunnel previews#135
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (3)
🚧 Files skipped from review as they are similar to previous changes (3)
📝 WalkthroughWalkthroughThis change adds protected Cloudflare Quick Tunnel support to ChangesQuick Tunnel publishing
Estimated code review effort: 4 (Complex) | ~60 minutes Sequence Diagram(s)sequenceDiagram
participant CLI
participant Preview as serve-sim preview
participant Tunnel as cloudflared
participant Remote as Browser
CLI->>Preview: Start with --tunnel
Preview->>Tunnel: Spawn Quick Tunnel
Tunnel-->>Preview: Return public trycloudflare URL
Preview-->>CLI: Print publicUrl and persist tunnel state
Remote->>Preview: Request tokenized URL
Preview-->>Remote: Set access cookie and redirect
Remote->>Preview: Send cookie-authenticated request
Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
skills/serve-sim/scripts/check-prereqs.sh (1)
8-15: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueMake argument parsing strictly reject unexpected arguments.
Currently, if the script is invoked as
scripts/check-prereqs.sh --tunnel extra_arg, it accepts the--tunnelflag and silently ignores the extra argument. Usingshiftensures that any trailing unexpected arguments are correctly flagged as an error.♻️ Proposed refactor
TUNNEL_MODE=false if [[ "${1:-}" == "--tunnel" ]]; then TUNNEL_MODE=true -elif [[ "$#" -gt 0 ]]; then + shift +fi + +if [[ "$#" -gt 0 ]]; then echo "usage: $0 [--tunnel]" >&2 exit 2 fi🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@skills/serve-sim/scripts/check-prereqs.sh` around lines 8 - 15, Update the argument parsing around TUNNEL_MODE so that after recognizing --tunnel, the consumed argument is removed before validating remaining arguments. Ensure any trailing arguments cause the existing usage error and exit status, while preserving no-argument and --tunnel behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@skills/serve-sim/scripts/check-prereqs.sh`:
- Around line 8-15: Update the argument parsing around TUNNEL_MODE so that after
recognizing --tunnel, the consumed argument is removed before validating
remaining arguments. Ensure any trailing arguments cause the existing usage
error and exit status, while preserving no-argument and --tunnel behavior.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 57efd1d7-c16e-46e1-bd2f-a2d0a0d682b2
📒 Files selected for processing (12)
.gitignorepackages/serve-sim/README.mdpackages/serve-sim/src/__tests__/quick-tunnel.test.tspackages/serve-sim/src/__tests__/runtime-reexec.test.tspackages/serve-sim/src/index.tspackages/serve-sim/src/quick-tunnel.tspackages/serve-sim/src/runtime.tsskills/serve-sim/README.mdskills/serve-sim/SKILL.mdskills/serve-sim/evals/evals.jsonskills/serve-sim/references/tunnels.mdskills/serve-sim/scripts/check-prereqs.sh
|
Here's a preview of serve-sim running over the internet on my iPhone. trim.CF10B2B2-ECAB-41D4-A07B-68B3954735AD.MOV |
Summary
This adds an opt-in Cloudflare Quick Tunnel mode to
serve-simso the full simulator preview can be opened from a remote computer or mobile browser without exposing a LAN listener or using a remote-desktop session.The new workflow is available through:
--publicis retained as a hidden alias for--tunnel. Quick Tunnel mode requires an existingcloudflaredinstallation, but does not require a Cloudflare account or login.The implementation includes an application-level access gate because a Cloudflare Quick Tunnel provides transport and a random hostname, not identity authentication. It also makes the tunnel lifecycle part of the existing
serve-simprocess lifecycle, including detached startup, diagnostics, ownership validation, and cleanup.Motivation
serve-simalready exposes a complete browser-based simulator control surface, but its normal preview URL is local to the Mac running Simulator. Reaching that preview from another device otherwise requires LAN connectivity, a VPN, manual reverse-proxy setup, or an RDP-style session.This change makes temporary remote access a deliberate CLI choice while preserving the existing local default:
serve-simbehavior is unchanged.127.0.0.1.cloudflaredpublishes that loopback origin through a temporarytrycloudflare.comURL.User-facing behavior
Attached mode
The CLI prints both the local URL and a tokenized public URL. The process stays attached to the terminal, and
Ctrl+C,SIGTERM, orSIGHUPstops the preview and its ownedcloudflaredchild.Detached mode
The launcher waits until the simulator preview and Quick Tunnel are ready, then returns JSON containing
publicUrl,localUrl, process IDs, selected devices, the bound port, and the normalized launch configuration.serve-sim --killstops the detached preview owner and itscloudflaredchild.If an identical detached tunnel is already running, the command returns that state. If devices or preview options differ, it fails with an explicit instruction to stop the existing tunnel first instead of silently returning the wrong preview.
Missing dependency
If
cloudflaredis absent, tunnel mode exits before booting or publishing the preview and prints the Homebrew install command:The command passes
--config /dev/nulltocloudflaredso a user-level named-tunnel configuration cannot interfere with Quick Tunnel startup.Access protection
Quick Tunnels do not add Cloudflare Access or an identity login, so
serve-simprotects the public control surface itself:SameSite=Strictcookie; public HTTPS requests also receive theSecureattribute.Originheader must match the exact tunnel origin, preventing a siblingtrycloudflare.compage from driving the control surface with an existing cookie.127.0.0.1; tunnel mode rejects a conflicting--hostvalue.Local CLI commands continue to use the credential-free loopback URLs stored in the existing per-device state files. The access gate allows those requests only when the request host is loopback and no proxy forwarding protocol is present. Forwarded requests remain protected even if they present a loopback
Hostheader.The complete URL is still a credential: anyone who receives it can view and control the simulator and use preview features that execute commands on the host. The README and bundled AI skill call this out directly and recommend a managed Cloudflare Tunnel with Access for stable hostnames or identity policies.
Process ownership and lifecycle
The tunnel owner writes owner-only state and diagnostics under the existing runtime-state directory:
Both files are mode
0600. The log follows the project's existing persistent runtime diagnostics convention and records lifecycle events pluscloudflaredoutput without writing the private access token.Lifecycle handling includes:
SIGTERMtoSIGKILL, avoiding stale PID reuse.cloudflaredtermination when the preview owner exits through normal signal paths.caffeinate -wcompanion for deliberately detached public previews; it exits with the preview owner.Detached launch identity
Detached state persists a normalized launch signature containing:
An existing tunnel is reused only when this signature matches exactly. Legacy state without a launch signature is not silently reused.
Runtime re-execution fix
Both regular
--detachand tunnel detachment re-execute the CLI. npm/npx commonly invokes the package through an extensionless.bin/serve-simsymlink, which cannot be classified by filename extension.Re-execution now classifies the runtime through
process.execPath:process.argv[1], even when the entrypoint is extensionless./$bunfs/...entrypoint.This preserves compiled-binary behavior while fixing both the existing npm/npx
--detachpath and the documentednpx serve-sim --tunnel --detachpath.Startup timing and diagnostics
The detached launcher previously used a fixed deadline that could be shorter than the child process's supported startup behavior. Its deadline now includes:
simctl bootstatusIf startup still fails, the launcher terminates the detached process group and surfaces the tail of the persistent tunnel log instead of leaving an orphaned preview or tunnel.
Review findings addressed
This version includes regression coverage and fixes for the blocking review findings found during local testing:
.playwright-mcp/logs and snapshots are ignored and are not part of the published change set.Documentation and AI skill
The package README now documents:
--tunneland detached usagecloudflaredinstallation and failure behaviorThe bundled
serve-simskill now includes:scripts/check-prereqs.sh --tunnelreferences/tunnels.mdworkflowValidation
Automated checks:
bun run typecheck bun run lint bun run packages/serve-sim/build.ts bun test packages/serve-sim/src/__tests__/bundle-portability.test.ts \ packages/serve-sim/src/__tests__/runtime-reexec.test.ts \ packages/serve-sim/src/__tests__/quick-tunnel.test.ts jq empty skills/serve-sim/evals/evals.json bash -n skills/serve-sim/scripts/check-prereqs.shResults:
Manual CLI validation covered:
serve-simentrypoint.event-logHTTP access during tunnel mode.tapWebSocket access during tunnel mode.401for unauthenticated forwarded traffic.Ctrl+Cduring detached startup leaving no preview process,cloudflaredprocess, state file, or listening port.serve-sim --killand direct owner termination cleaning up the ownedcloudflaredprocess and runtime state.cloudflared 2026.7.1.The broader real-Simulator suite produced 375 passes and 3 skips. Two teardown-time failures were investigated separately: the camera-helper shutdown test passed on isolated rerun, while all 10 UI-settings assertions pass but its serial
afterAllreset exceeds Bun's default hook timeout on this machine.Scope and compatibility
simMiddlewarepackage API is unchanged by tunnel authentication.>=20).cloudflaredis required only when the user explicitly selects tunnel mode.Summary by CodeRabbit
New Features
serve-sim, including--tunneland--publictokenized URL sharing.--kill.Documentation
cloudflared), security notes, and updated tunnel examples/evals.Tests
Chores