Skip to content

Cloud attach-endpoint: report vmKind (owner only for the caller's own personal VM) - #26222

Merged
teamleaderleo merged 2 commits into
mainfrom
vmkind-attach-main
Oct 27, 2026
Merged

teamleaderleo merged 2 commits into
mainfrom
vmkind-attach-main

Conversation

@teamleaderleo

@teamleaderleo teamleaderleo commented Oct 27, 2026 •

Copy link
Copy Markdown
Collaborator

What

POST /api/vm/:id/attach-endpoint now answers a top-level vmKind: "owner" | "team" | null on every transport (cmux-remote, websocket).

The Mac app will use it to give up its local sandbox for the caller's own session only when the Cloud API says the machine is the caller's own personal machine. The guest has passwordless sudo, so no in-guest marker can be trusted for this. The app reads the field per link and never caches it; a missing, null or other value stays sandboxed. The app and acpmux sides are separate PRs.

The rule (strict)

New vmKindForCaller(row, callerUserId) in web/services/vms/vmKind.ts:

  • "owner" only when the machine is on the caller's own personal account (owner_team_id equals the caller's user id, the synthetic personal team) and the caller created it (user_id equals the caller).
  • "team" for every Stack team, a one-member team included, and for any machine the caller can reach but did not create. A team member attaching to a teammate's machine gets "team".
  • null when the row has no usable billing owner (blank owner_team_id). The access check already refuses such a row, so in practice clients see owner or team.

resolveVmGuestKind and its callers (the guest's /etc/cmux/vm-kind via /api/vm/reflection/kind) are unchanged. On main that function calls a one-member team owner and re-asks every minute; the attach answer deliberately does not reuse it, so it can't turn into owner for a team.

owner_team_id is text NOT NULL DEFAULT '' on main and feat-cmux-next alike, so "personal account" means owner_team_id = user_id on both. There is no null case.

Where production serves this

Both the stable app and the nightly-next app call https://cmux.com/api/vm/:id/attach-endpoint:

  • classic: Packages/macOS/CmuxCloud/Sources/CmuxCloud/Environment/AuthEnvironment.swift:324-336, where a Release build is always https://cmux.com;
  • next: Packages/macOS/CmuxNext/Sources/CmuxNextCloud/Config/CloudConfiguration.swift:69,95-99 and API/CloudAPIClient.swift:117-122, where a Release build uses apiBaseURL = https://cmux.com.

cmux.com is the Vercel web/ app. web/vercel.json deploys main only, and a live request answers server: Vercel, x-matched-path: /api/vm/[id]/attach-endpoint. So this lands on main for production. A twin PR carries the same change to feat-cmux-next so the branches don't drift.

Tests

web/tests/vm-attach-vm-kind.test.ts, through openVmCmuxRemote and openAttachEndpoint, plus the pure function:

  • the creator on their personal machine gets owner;
  • a team machine gets team, for its creator too;
  • another account that can attach gets team, never owner;
  • a one-member team gets team;
  • an unusable owner gets null, and its attach is refused.

Three existing vm-workflows equality checks now expect the extra field.

Linux CI: 14 related files, 325 pass and 0 fail; tsgo, eslint and complexity are clean.

Each test fails without its part of the change:

  • with the workflow wiring removed, 7 tests fail;
  • with owner for any personal machine whoever calls, the "another account" tests fail (2);
  • with a one-member team as owner, the one-member test fails (1).

Risk

The response gains a field; Swift decoders ignore unknown keys. A wrong owner would let a session skip the local sandbox, so the rule fails closed: only the exact creator-on-personal-account case is owner.

Agent session: agent session

🤖 Generated with Claude Code


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

Summary by CodeRabbit

  • New Features
    • VM attach responses now include a caller-specific classification: a VM is labeled “owner” when the caller matches both its user and billing owner; otherwise, it is labeled “team.”
    • The classification appears in standard and remote attach responses, including successful recovery results.
  • Bug Fixes
    • VMs with a blank or whitespace-only billing owner are handled as unavailable during attach workflows.

POST /api/vm/:id/attach-endpoint now answers vmKind: "owner" | "team" | null.
"owner" only when the machine is on the caller's own personal account
(owner_team_id is the caller's user id) and the caller created it. Every
Stack team, a one-member team included, is "team", and so is a machine the
caller can reach but did not create. A row with no usable billing owner is
null. The Mac app drops its local sandbox for its own session only on
"owner"; resolveVmGuestKind and its callers are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-4ba8980ae4e8eecb82d6
@github-actions

Copy link
Copy Markdown
Contributor

All contributors have signed the CLA ✍️ ✅
Posted by the CLA Assistant Lite bot.

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Owned by an agent session · session

@coderabbitai

coderabbitai Bot commented Oct 27, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

No actionable comments were generated in the recent review.

Recent review info
Run configuration
Commits

Reviewing files that changed from the base of the PR and between c2a71bd and cd4af3a.

Files selected for processing: 2
  • web/services/vms/vmKind.ts
  • web/tests/vm-attach-vm-kind.test.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 4 remain after this review.

Walkthrough

The change adds caller-specific VM kind classification and includes vmKind in cmux-remote, legacy attach, and shared attach results. Tests cover personal and team VM cases, caller identity matching, and missing billing owners.

Changes: Caller-specific VM kind

Layer / File(s) Summary
Classify VM kind
web/services/vms/vmKind.ts, web/tests/vm-attach-vm-kind.test.ts
vmKindForCaller returns owner when the caller ID exactly matches the VM user ID and billing owner. It returns team for other cases with a nonblank billing owner, and null when the billing owner is blank. Tests cover these conditions.
Include VM kind in attach results
web/services/vms/workflows.ts, web/tests/vm-attach-vm-kind.test.ts, web/tests/vm-workflows.test.ts
The cmux-remote, legacy attach, and shared attach results include the caller-specific vmKind. Endpoint tests cover personal and team VM cases, and workflow tests expect team in successful results.

Priority: Normal

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Feature

Possibly related PRs

  • manaflow-ai/cmux#26182: Both changes classify VMs as owner or team. That PR records the kind for newly created Cloud VMs; this change includes it in attach responses.
Merge Risk: Minimal · up to cd4af

No merge-blocking risk was identified; the change is ready to merge.

Pre-merge checks: Passed 23 · Failed 2

Failed Failed checks: 2 warnings

Check name Status Explanation Resolution
Description check Warning The description gives a detailed summary, implementation rule, production context, testing results, and risk analysis. However, it does not use the required Summary, Testing, Changelog, Proof, and Che… Reformat the description using the repository template. Add ## Summary, ## Testing, ## Changelog, ## Proof, and ## Checklist sections. Move the existing content into the appropriate sections, add a present-tense changelog line or none, st…
Docstring Coverage Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Documentation-only edits and deletions within surv… Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 23 passed
Check name Status Explanation
Title check Passed The title clearly identifies the main change: attach-endpoint responses now report caller-specific vmKind, with owner limited to the caller’s personal VM.
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Cmux Cloud Persistent Session And Early Input Passed PASS. The reviewed diff only adds vmKindForCaller and appends vmKind to existing attach results. It does not create a client, carrier, event socket, renderer, readiness gate, or input path. Existi…
Cmux Swift Actor Isolation Passed The pull request changes only four TypeScript files under web/services and web/tests. The authoritative diff contains no Swift files or production Swift changes, so it cannot introduce or worsen Swift…
Cmux Swift Blocking Runtime Passed PASS. The pull request changes only TypeScript service and test files. It introduces no production Swift changes, so it does not introduce or expand Swift blocking or timing-based synchronization.
Cmux Browser Automation Off-Main Passed PASS: The pull request changes only web/services/vms/vmKind.ts, web/services/vms/workflows.ts, and related web tests. It does not change Sources/TerminalController.swift or `Packages/macOS/CmuxC…
Cmux Expensive Synchronous Load Passed PASS: The pull request changes only TypeScript files under web/ and adds no Swift files or Swift call-site changes. Therefore it does not add or move an expensive synchronous agent-history load onto…
Cmux Cache Substitution Correctness Passed The pull request adds a per-request vmKindForCaller value to attach responses. It does not replace a fresh authoritative read with a cached or opportunistic value, and it does not change a persisten…
Cmux No Hacky Sleeps Passed PASS: The production diff only adds vmKindForCaller and attaches its result to workflow responses. It adds no sleep, timer, polling, fixed delay, backoff, or wall-clock synchronization. The new te…
Cmux Algorithmic Complexity Passed PASS: The production changes add one constant-size identity check in web/services/vms/vmKind.ts and add vmKind to endpoint result objects in web/services/vms/workflows.ts. They do not scan scala…
Cmux Swift Concurrency Passed The pull request changes only TypeScript service and test files under web/. The authoritative diff contains no Swift files or Swift code, so it does not introduce or expand any Swift concurrency patte…
Cmux Swift @Concurrent Passed PASS: The pull-request diff changes only TypeScript files under web/services and web/tests. It introduces no Swift functions, call sites, or actor-isolation changes, so the Swift @concurrent criteria …
Cmux Swift Package Boundaries Passed The reviewed diff changes only TypeScript service and test files. It contains no Swift production changes, so it does not introduce or expand logic across a Swift package boundary.
Cmux Swiftpm Lockfiles Passed The pull request changes only four TypeScript service and test files under web/. It does not change SwiftPM packages, Package.swift files, Package.resolved lockfiles, Xcode project references, .gitign…
Cmux Swift Logging Passed The PR changes only TypeScript files under web/. It contains no Swift file changes, so it introduces or materially changes no production Swift logging covered by the policy.
Cmux User-Facing Error Privacy Passed The production diff adds only vmKind to successful attach API responses. The route returns this value through jsonResponse at web/app/api/vm/[id]/attach-endpoint/route.ts:87,111, and the macOS c…
Cmux Full Internationalization Passed PASS. The diff adds only the machine-readable vmKind API field and the exact owner/team/null protocol values. The attach route returns this field as JSON for Mac client logic. It adds no human…
Cmux Swiftui State Layout Passed The pull request changes only TypeScript files under web/services and web/tests. It contains no Swift or SwiftUI changes, so the SwiftUI state-layout rules do not apply.
Cmux Architecture Rethink Passed PASS: The reviewed diff changes only web TypeScript services and tests. It adds no Swift files or Swift architecture changes, so the Swift architectural-rethink failure conditions do not apply.
Cmux Swift Auxiliary Window Close Shortcuts Passed The pull request changes only four web TypeScript/test files. The reviewed diff contains no Swift or window declarations, so it does not trigger the auxiliary-window close-shortcut rule.
Cmux Source Artifacts Passed All four changed paths are intentional TypeScript source or test files: web/services/vms/vmKind.ts, web/services/vms/workflows.ts, and the two web/tests files. The diff adds the `vmKindForCaller…
Cmux No Test Or Debug Seam In Production Source Passed The pull request changes only web TypeScript and test files. It changes no Swift file under a production Sources/ path, so it cannot introduce a test or debug seam covered by this check.
Full details: Cmux Cloud Persistent Session And Early Input

Explanation

PASS. The reviewed diff only adds vmKindForCaller and appends vmKind to existing attach results. It does not create a client, carrier, event socket, renderer, readiness gate, or input path. Existing access checks, provider attach calls, lease recording, and session flow remain unchanged. The added computation runs after the existing remote or websocket operation and does not weaken auth, idempotency, revision, or lease fences.

Full details: Cmux Swift Actor Isolation

Explanation

The pull request changes only four TypeScript files under web/services and web/tests. The authoritative diff contains no Swift files or production Swift changes, so it cannot introduce or worsen Swift 6 actor-isolation issues.

Full details: Cmux Browser Automation Off-Main

Explanation

PASS: The pull request changes only web/services/vms/vmKind.ts, web/services/vms/workflows.ts, and related web tests. It does not change Sources/TerminalController.swift or Packages/macOS/CmuxControlSocket/Sources/CmuxControlSocket/Wire/ControlCommandExecutionPolicy.swift. The diff adds no browser socket commands, WebKit waits, worker routing, or policy tests. The browser automation rule is not applicable.

Full details: Cmux Expensive Synchronous Load

Explanation

PASS: The pull request changes only TypeScript files under web/ and adds no Swift files or Swift call-site changes. Therefore it does not add or move an expensive synchronous agent-history load onto the main actor or an interactive Swift path.

Full details: Cmux Cache Substitution Correctness

Explanation

The pull request adds a per-request vmKindForCaller value to attach responses. It does not replace a fresh authoritative read with a cached or opportunistic value, and it does not change a persistence, history, undo, or snapshot path. The changed workflow still obtains the VM through requireAccessibleUserVm; the new value is computed from that row and is explicitly not stored.

Full details: Cmux No Hacky Sleeps

Explanation

PASS: The production diff only adds vmKindForCaller and attaches its result to workflow responses. It adds no sleep, timer, polling, fixed delay, backoff, or wall-clock synchronization. The new test code uses async calls but adds no timing scaffolding. Existing timing code in workflows.ts is unchanged.

Full details: Cmux Algorithmic Complexity

Explanation

PASS: The production changes add one constant-size identity check in web/services/vms/vmKind.ts and add vmKind to endpoint result objects in web/services/vms/workflows.ts. They do not scan scalable collections, sort/filter per event, perform in-memory joins, or introduce a slower algorithm on a 1000-record path. The added tests are test-only and are exempt by the rule.

Full details: Cmux Swift Concurrency

Explanation

The pull request changes only TypeScript service and test files under web/. The authoritative diff contains no Swift files or Swift code, so it does not introduce or expand any Swift concurrency pattern.

Full details: Cmux Swift `@Concurrent`

Explanation

PASS: The pull-request diff changes only TypeScript files under web/services and web/tests. It introduces no Swift functions, call sites, or actor-isolation changes, so the Swift @concurrent criteria do not apply.

Full details: Cmux Swiftpm Lockfiles

Explanation

The pull request changes only four TypeScript service and test files under web/. It does not change SwiftPM packages, Package.swift files, Package.resolved lockfiles, Xcode project references, .gitignore files, workflows, or dependencies. The SwiftPM lockfile policy is therefore not triggered.

Full details: Cmux User-Facing Error Privacy

Explanation

The production diff adds only vmKind to successful attach API responses. The route returns this value through jsonResponse at web/app/api/vm/[id]/attach-endpoint/route.ts:87,111, and the macOS client calls that product API. The new values are owner, team, or null, which do not expose implementation details. No user-facing error, alert, command output, or recovery copy changed. Provider-specific values appear only in developer comments and tests, which the rule allows.

Full details: Cmux Full Internationalization

Explanation

PASS. The diff adds only the machine-readable vmKind API field and the exact owner/team/null protocol values. The attach route returns this field as JSON for Mac client logic. It adds no human-facing Swift or web text, metadata, or locale message keys. Protocol and machine-marker tokens are explicitly allowed by the internationalization rule.

Full details: Cmux Source Artifacts

Explanation

All four changed paths are intentional TypeScript source or test files: web/services/vms/vmKind.ts, web/services/vms/workflows.ts, and the two web/tests files. The diff adds the vmKindForCaller implementation, workflow wiring, and focused tests. No local output, generated logs, screenshots, recordings, temporary directories, caches, build artifacts, dependency checkouts, or broad scratch directories appear in the changed-file inventory.

Full details: Description check

Explanation

The description gives a detailed summary, implementation rule, production context, testing results, and risk analysis. However, it does not use the required Summary, Testing, Changelog, Proof, and Checklist sections. It also omits the required changelog entry, proof statement, and checklist status.

Resolution

Reformat the description using the repository template. Add ## Summary, ## Testing, ## Changelog, ## Proof, and ## Checklist sections. Move the existing content into the appropriate sections, add a present-tense changelog line or none, state why visual proof is not applicable, and mark or explain each checklist item.

Full details: Docstring Coverage

Explanation

Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Documentation-only edits and deletions within surviving functions are included; unchanged diff context and fully deleted functions are excluded. Analyzed 9 functions across 4 files.

Resolution

Write docstrings for the functions missing them to satisfy the coverage threshold.

Finishing Touches: 💡 1
📝 Generate docstrings: 💡
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

A creator id that matches the caller only after trimming is not the
caller, so it never gets "owner".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-4ba8980ae4e8eecb82d6
@cursor

cursor Bot commented Oct 27, 2026

Copy link
Copy Markdown

Bugbot needs on-demand usage enabled

Bugbot uses usage-based billing for this team and requires on-demand usage to be enabled.

A team admin can enable on-demand usage in the Cursor dashboard.

@teamleaderleo
teamleaderleo merged commit 3596445 into main Oct 27, 2026
73 checks passed
@teamleaderleo
teamleaderleo deleted the vmkind-attach-main branch October 27, 2026 15:13
teamleaderleo added a commit that referenced this pull request Oct 31, 2026
…e-member team (#28479)

* Cloud attach-endpoint vmKind: owner for the creator's machine on a one-member team

The classic attach answer said `team` for every Stack team, including a
personal Stack team whose only member is the creator. Accounts made with a
personal team get every machine on that team, so the Mac app never sent
`vm_kind: "owner"` and cmux-tui refused agent chats with
agent_session.host_unverified on the classic route.

vmKindForCaller now answers `owner` for a machine the caller created on a
Stack team whose member list, read for this attach with the bounded
listTeamMemberIdsWithTimeout (resolveVmGuestKind's read), is exactly the
caller. A second member, a missing team, an unread, failed or timed-out list
all answer `team`. The read runs only for that case and overlaps the endpoint
open. Reverses the one-member choice of #26222.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-aa0f0a21b40fda1441b8

* test(vm-route-auth): type-safe team directory assertion

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-aa0f0a21b40fda1441b8

* test(vm-kind): a second member flips the same machine to team on the next attach

Review note on #28479: test the transition with one directory, not two.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-aa0f0a21b40fda1441b8

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
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