Skip to content

feat: macOS desktop role and managed browser (PR4) - #501

Draft
chruffins wants to merge 3 commits into
feat/macos-guest-servicefrom
feat/macos-desktop-browser
Draft

chruffins wants to merge 3 commits into
feat/macos-guest-servicefrom
feat/macos-desktop-browser

Conversation

@chruffins

@chruffins chruffins commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor

Stack

PR4 of the six-PR macOS integration stack; based on #500 (feat/macos-guest-service). Restacked onto the reviewed #500 head 0cf36ae; PR4 commits are now 25087f7 and 0634b40. Reviewer process-group/timeout and readiness fixes are preserved. Keep draft. No live service or VM changes were made for this PR.

Implemented

  • Add a separate --role desktop to the shared Darwin agent, retaining the default system GuestService on 2222. The non-root desktop role serves a versioned HTTP interface on host-CID-only native vsock 2223; no privileged command bridge or guest TCP listener.
  • Declare desktop_agent_uid separately from system guest_agent capability. Live handshake checks version, Darwin/arm64, selected UID, console/GUI-session readiness, managed browser ownership/readiness. VMM Running and root-agent readiness remain separate.
  • Add fixed headful Chrome launch under the selected Aqua user, private user profile with ownership/mode/symlink checks, allowlisted environment, child-exit tracking and PID-scoped loopback-listener ownership verification before Chrome discovery. Never adopt an arbitrary existing debugging server. Browser lifetime is not tied to an API request, viewer or CDP disconnect.
  • Add JWT/instance-write protected instance status, explicit start, bounded discovery and browser/page WebSocket routes using existing resource resolution. Read-only/unauthenticated admission precedes resolution/dial. Existing scoped-token resource model is preserved; no new tenant ownership model is claimed.
  • Require trusted macos_desktop_origin configuration; default disabled. Never use incoming Host/Forwarded for debugger URLs. Present Origin must match configured origin. Strip API credentials/cookies/origin/arbitrary headers from both management and CDP transport.
  • Fixed guest/browser upstreams; reject arbitrary paths/arguments/bodies/queries, redirects, invalid/oversized discovery and unsafe debugger URLs. Rewrite discovery to canonical instance ID. Bound status JSON, launch time, concurrent sessions and launch concurrency; release session slots on disconnect.
  • Document explicit isolated-guest provisioning and provide an Aqua LaunchAgent plist example. No installation, bootstrap or TCC changes are automatic.

Local validation

Bounded, allowlisted test environment; nice -n 10, GOMAXPROCS=1, GOMEMLIMIT=256MiB, -p 1.

  • Race tests pass on the restacked head: full lib/desktop, lib/system/guest_agent, lib/guest, cmd/api/config, lib/scopes; focused desktop/macOS/disconnect API/instances/images/shim tests. Separate disposable combined-source QA of latest macOS guests 1/6: native VZ runtime and instance lifecycle #498–500 plus PR4-only changes also passes; macOS guests 2/6: OCI machine-image integration #499/macOS guests 3/6: Darwin shared GuestService #500 branch histories still lack the newest macOS guests 1/6: native VZ runtime and instance lifecycle #498 commits, so that combined-source result is distinguished from standalone branch validation.
  • Synthetic real JWT/write-scope and resource-resolver tests; wrong UID/root/version, missing login, unsupported/stopped/disabled capabilities, cross-origin, unknown resource, bounded handshake, serialized launch, cancellation, discovery rewriting/credential isolation, actual WebSocket echo/reconnect and session limit/release.
  • Darwin-specific tests inspect fixed command/environment, listener ownership parsing, private profile and symlink handling. They do not execute Chrome or install anything.
  • Darwin CGO0 desktop/agent tests pass (native listener explicitly unsupported without CGO). Darwin CGO1 agent builds. API main compiles. LaunchAgent plist passes plutil -lint.
  • Linux/arm64 CGO0 desktop and agent test binaries cross-compile, not executed. Linux API test cross-build blocked by missing pre-existing embedded cloud-hypervisor/Caddy binaries, not claimed passing.
  • autoreview --mode local attempted on implementation: reviewer authentication failed with 401; no independent automated review result.

Remaining in this draft / explicit limitations

  • No authorized live guest provisioning/handshake/launch/shutdown/recovery test yet; native desktop listener, Aqua detection, lsof PID ownership, real Chrome startup and viewerless behavior are not live-validated by these unit tests. Existing live guest/API/Chrome and earlier draft worktrees remain untouched.
  • OS desktop capture/input, TCC handling and supported viewer attach/detach/resize are not implemented in this checkpoint; remain in PR4 display scope. CDP browser screenshots are not an OS-desktop capture contract.
  • Browser crash replacement requires explicit start. Agent restart adoption of a surviving Chrome is deliberately unsupported until ownership/recovery is proven; it refuses an unmanaged occupied debugging port rather than guessing.
  • Worker-specific debugger paths, arbitrary HTTP CDP management paths and DevTools frontend hosting remain unsupported. CDP itself grants full browser authority, not a website/command sandbox.
  • Coordinate Windows session/capability semantics before expanding shared proto/API contracts; this patch changes no GuestService protobuf fields.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes using default effort and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit f170546. Configure here.

Comment thread lib/instances/macos.go
}
req.OverlaySize = *img.SizeBytes // Reserve the writable boot disk, not a Linux overlay.
req.SkipGuestAgent = true
req.SkipGuestAgent = req.SkipGuestAgent || !img.MacOS.GuestAgent

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Desktop capability tied to system agent

High Severity

Instance create sets SkipGuestAgent whenever the image omits system guest_agent, and desktop routes then treat that flag as a hard disable. A template that only declares desktop_agent_uid therefore stores SkipGuestAgent and gets 501 on every CDP call, even though the two capabilities are documented as independent and guestAgentEnabled already ignores undeclared system agents without this flag.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit f170546. Configure here.

Comment thread cmd/api/api/cdp.go
cancel()
if err != nil {
http.Error(w, "selected desktop agent unavailable or incompatible", 503)
return

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Start maps session-not-ready to 503

Medium Severity

POST /cdp/start treats every failed Probe as 503 agent-incompatible. The guest already returns 409 when the Aqua session is not ready, but Probe only checks for HTTP 200, so a logged-out or non-GUI console is reported as an unavailable desktop agent.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit f170546. Configure here.

@chruffins

Copy link
Copy Markdown
Contributor Author

Real isolated macOS guest QA passed (reviewed combined PR1–3 + PR4 patches): manually deployed current Darwin shared binary as a nonroot gui/501 Aqua QA LaunchAgent on native2223. Opted desktop UID501 into only the private QA instance metadata, configured trusted loopback desktop origin, and exercised normal authenticated API CDP start/discovery/browser WebSocket/navigation/evaluation/PNG screenshot/reconnect. Handshake confirmed Darwin/arm64, UID/console501, GUI session and owned Chrome155.0.8059.40. Browser WebSocket URL stayed unchanged after viewer socket close, and authenticated reconnect worked.

Killed only Chrome PID proven to match the fixed binary and private Hypeman profile: discovery returned409 until explicit start200, then the full CDP test passed again. Live unauthenticated401/read-only403/untrusted-Origin403 admission passed. Empty origin correctly disables routes503 and body-bearing start rejects400. launchctl kickstart -k of the QA agent followed by explicit start returned200; this does not establish surviving-browser adoption or occupied-port rejection (launchd process-group teardown differs from an isolated agent crash).

This is manual isolated deployment/capability opt-in, not automatic image provisioning; screenshot is CDP browser rendering, not OS capture/input/TCC/viewer resize. Root system capability remained disabled. Original guest/storage/API untouched; QA VM/API stopped and slot released. Browser restart ownership remains a separate gate.

@chruffins
chruffins force-pushed the feat/macos-guest-service branch 4 times, most recently from e9fa76d to a1ed358 Compare October 9, 2026 19:49
@chruffins
chruffins force-pushed the feat/macos-desktop-browser branch from 0634b40 to 8ba7ec6 Compare October 9, 2026 21:53
@chruffins
chruffins force-pushed the feat/macos-guest-service branch from a1ed358 to 243ce9a Compare October 9, 2026 21:53
@chruffins

Copy link
Copy Markdown
Contributor Author

Simplification update at 8ba7ec6: guest NewCDPForwarder carries fixed-upstream discovery unchanged; authenticated host NewCDPProxy alone validates discovery and rewrites public URLs. Both retain body/path/query/encoding admission, credential/header isolation, redirect policy and fixed upstream; guest session/browser ownership remains enforced. Tests cover both discovery boundaries and two-hop WebSocket round trips. Post-restack desktop/API/agent/client/scope/config focused race suites passed 3 runs; focused CGO0 admission tests pass. No guest/VM changes or new OS capture/input/TCC/adoption proof.

All PRs remain draft. This is source-level/synthetic validation, not a new live boot or production build proof. Default Codex independent review was attempted but is still blocked by authentication (HTTP401). Published atomically after checking reviewer heads with explicit per-ref force-with-lease; prior heads preserved locally.

@chruffins
chruffins force-pushed the feat/macos-desktop-browser branch from 8ba7ec6 to adf2d41 Compare October 11, 2026 02:22
@chruffins

Copy link
Copy Markdown
Contributor Author

Restacked onto the root readiness/shutdown corrections in PR500: current head adf2d41. Atomic explicit-lease push preserved reviewer heads. Focused instances/desktop/API/agent/client regression tests pass race,count3. Root normal-API QA passed in an isolated manually provisioned guest; this does not add durable desktop adoption, screen capture/input, automatic image provisioning or full macOS build proof. PR remains draft.

@chruffins
chruffins force-pushed the feat/macos-desktop-browser branch from adf2d41 to e852ee6 Compare October 11, 2026 04:41
@chruffins
chruffins force-pushed the feat/macos-guest-service branch from ae3685d to c336b30 Compare October 11, 2026 04:41

This branch has not been deployed

No deployments
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