cloud: share a port with your team from the sidebar
Summary
cloud machine port rows get a link button (always visible) and a "Copy Share Link" menu item. clicking it gives you an https link to that port that only signed-in members of the machine's team can open (owner-only on a personal machine). signed out you get the cmux sign-in wall, signed in on another team you get "You don't have access".
the backend was already on main (publications, freestyle forward-auth, the /cloud/access handoff). this PR is the app side:
- share flow (
CloudPortShareServicein CmuxCloud): reuse the port's live cmux-generated publication or create one with the server default (team for a team machine), then wait until it'sactiveand the link itself answers. "answers" is a cookie-free HEAD: cmux's forward-auth returns 401 for a protected link without minting a sign-in or reaching the machine. Public links accept ordinary app responses once the edge forwards; edge 5xx and unknown protected routes remain not ready. polling creates again (idempotent on the fixed hostname, resumes a provisioning or unavailable row, works on a teammate's row), treats 409 and 503 busy as "not yet", and gives up after about a minute with "The link is still being set up". it polls because the service has no push channel for readiness; delays and sleep are injected. - team scope: publication calls take an optional
scopeTeamID; share passes the machine's owning team, same asopenPort. - row state:
CloudPortShareStore(@Observable) keys progress by machine + port. spinner and "Creating link…", then a checkmark and "Copied to clipboard" for 2s, tooltip says who can open it. if the clipboard changed while the link was being made it isn't overwritten: the row says "Link ready" and the next click copies.
stacked on #17123 (web, optional CMUX_VM_PUBLICATION_FORWARD_AUTH_ORIGIN), which only matters for testing on tailnet-only dev stacks. builds on austin's #16771 (team default when access is omitted). overlaps with lawrence's #12285, which adds "Copy Proxy URL (cmux.sh)" on port rows through the same POST /api/vm/publications; happy to fold into whichever should carry it.
| Preview (share a port: creating link, then copied to clipboard) |
|---|
Testing
- live on the dev backend (tag
port-share), clicking share in the tagged app: "Creating link…" then "Copied to clipboard", link opens in incognito to the sign-in wall, signed in as a team member the page loads (video above, build of b963458). with the forward-auth tunnel on the dev VM, 30/30 signed-out requests got the sign-in redirect; from a tunnel on my mac, slow round trips tripped freestyle's 1.5s forward-auth timeout and showed its 503 (dev only, prod forward-auth is cmux.com). - CLI on dev:
cmux cloud domains publish <vm> 8000with no flags gives team access, active in 29s. - Earlier implementation evidence:
swift test --filter CloudPortSharein CmuxCloud passed 12/12. The current head adds cancellation-at-await, safe HEAD transport, public-edge readiness, and replacement-operation fencing; hosted macOS package/build lanes are the execution gate for those additions. python3 scripts/verify-local.py --repo .: 7/7 (localization parity across 9 locales, defaultValue parity, swift syntax).- review findings and resolutions are recorded in the PR discussion. Current head includes cancellation fencing, operation identity for replacement shares, safe HEAD probing, deterministic browser render-host fixtures, and the fork-safe migration-plan fallback. The video is from the original implementation build.
Changelog
Added: Share a Cloud machine port with your team from the sidebar; the copied link opens for teammates after they sign in.
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.
Summary by cubic
Cloud machine port rows get a Share Link button and Copy Share Link menu item that copy an HTTPS link only signed-in members of the machine's team can open; signed-out visitors get the sign-in wall, and members of other teams get an access error. The branch also carries the full publication-edge-origin lineage through 0.65.0 and recent main fixes.
Share flow
- Reuses the port's existing cmux-generated link (custom domains left alone) or creates a team-access one for team machines, owner-only for personal ones.
- Polls by creating again: idempotent, resumes provisioning or unavailable rows, works on a teammate's row, and 409/503 mean "not yet".
- Copies only once the link answers 2xx/3xx or the forward-auth 401; public links aren't probed.
- Runs as the machine's owning team; won't overwrite the clipboard if it changed while the link was made.
- The button stays visible at rest, shows a spinner while creating, then an inline "Copied to clipboard" note.
Merged from publication-edge-origin and main
- Cloud: account directory survives team switches, restored panes leave when team access is gone, New Machine sheets and pop-ups size outside AppKit's layout pass, port scans of only diagnostics report unavailable, restored agent views reattach after relaunch, Cloud welcome is skipped on dev launches, and the 0.65.0 Cloud tab defaults on.
- Sessions stop replaying partial ANSI strings, browser panes show hovered link URLs (off by a setting), Install and Relaunch skips the quit confirmation, pane tabs close on middle click again, Ghostty's layer display callback detaches before the native surface free, and agent auto-resume honors retry-after hints and clears its counter after recovery.
- The CLI explains app/CLI version skew instead of raw
method_not_found, sanitizes socket text for the terminal, lists default shortcuts incmux welcome, and validates browser profile andworkspace createoption arguments. - Settings and shortcut search run off the main-thread render path; classic
cmux.jsonedits (including font sizes and sleepy mode) apply live with sanitized diagnostics, and settings parsers build one catalog section per parser instead of per key. - Release 0.65.0 defaults the Cloud tab on; Pro is sold yearly at $480/yr; Stripe webhook lease-contention events are replayed instead of paging; the control socket stays alive during automatic update.
- Web: coderouter organization listings stay inside their Stack deadline, Cloud diagnostics leases acknowledge by primary key and routine polls are sampled at ingest, hosted Subrouter is opt-in after
sr.cmux.comretired, Computer Use installs only a Developer ID signed helper, stuck account deletions resume now that the hosted tenant step is gone, and backend crons check in to Sentry. - iOS preserves System VPN permissions, filters the unsupported hotspot permission from TestFlight uploads, and adds Feed timing/scroll-stall telemetry tied to consent.
- CI moves trusted-token lanes onto ephemeral Blacksmith runners (including CLA jobs), names the failing test and whose it is, makes
gh-merge-greenwait for the cmux-next run on the exact head and excuse only failures the base branch also has, continues interrupted nightly notarizations, publishes nightly full feeds before Sparkle deltas, retries dSYM and attestation uploads, gates IndexNow to production main, plans migrations without the API when none changed, scopes Web complexity to web paths, and rescues hosted and superseded side-lane jobs. reload.sh --releasebuilds the tagged app in Release;workspaceColors.brightenInDarkModeshows workspace colors as chosen in dark mode.
[!NOTE]
Medium Risk
New release continuation workflow publishes signed nightly assets and retags channels; mis-validation could block or mis-publish builds, while runner/rescue changes affect required PR checks broadly.
Overview
This diff is CI and release plumbing (no app/cloud UI changes in the patch shown).
Nightly notarization adds Continue nightly notarization, which picks up recovery artifacts from Nightly macOS build, polls Apple from Linux, staples on macOS only after acceptance, then publishes DMGs/feeds/R2 and optionally generates Sparkle deltas afterward.
Runner and quota hardening moves many trusted-token workflows off fixed ubuntu-24.04 onto CI_TRUSTED_RUNNER / LINUX_RUNNER (triage, migrations, attribution, manual-dispatch guard). Backend migrations can skip the PR files API when backend/db/migrations matches the base tree. New CI hosted queue rescue reruns CLA/fast-guard runs that were cancelled after ~15 minutes with no runner.
Other CI tweaks: failure attribution also runs on workflow_run requested (pending comments); manual CI workflow_dispatch is limited to main; Blacksmith linux_arm64 label and CloudVPN profile naming are updated; GhosttyKit workflow adds CJK/shaping/layer teardown Zig tests; swift-warning-budget.tsv grows for browser portal AppKit isolation warnings; PR template Demo Video → Proof; inert cmux-next workflow stub for workflow_run subscribers.
Reviewed by Cursor Bugbot for commit f7b26fe39950a4d02a916cb73318eb988d687176. Bugbot is set up for automated code reviews on this repo. Configure here.
Summary by CodeRabbit
-
New Features
- Added share links for eligible forwarded ports on Cloud machines, with progress, success, and failure feedback.
- Added translations for port-sharing actions and statuses, plus restored Cloud machine plan messages across supported languages.
- Added an optional setting to use a separate origin for publication forward authentication.
-
Bug Fixes
- Improved Cloud sharing link readiness checks and retries, and made migration checks fall back to file details when Git checks fail.
- Improved sheet sizing and positioning as content changes or windows move.
- Corrected macOS managed-defaults handling for quoted values.