Skip to content

Cloud VM: a chat move in and folder trust need the caller's vmKind owner, never the VM's record - #26330

Merged
teamleaderleo merged 3 commits into
feat-cmux-nextfrom
hb-acpmux/vm-kind-move-trust
Oct 28, 2026
Merged

teamleaderleo merged 3 commits into
feat-cmux-nextfrom
hb-acpmux/vm-kind-move-trust

Conversation

@teamleaderleo

@teamleaderleo teamleaderleo commented Oct 27, 2026 •

Copy link
Copy Markdown
Collaborator

Built on #26323 (PR 3, merged as a6c49db), which adds the app's per-link vmKind answer (CloudAttachEndpoint.callerOwnsVM, CloudMachineLink.callerOwnsVM) and vm_kind on agent-session-start. This PR needs that field. It is now rebased onto feat-cmux-next after #26323, with patches identical to the reviewed stack (range-diff =).

The rule (claude-sr2, relayed by the area owner): "the kind comes from outside the guest. The client side (the app or the daemon that starts the remote session) asks the Cloud API which kind the VM is, for the signed-in account, and passes that to the remote start; the guest never decides." And: "Agents keep sudo in Cloud VMs". #26323 applied that rule to agent-session-start only. A chat move in and folder trust on a Cloud VM still trusted the guest's own /etc/cmux/vm-kind owner record, which any agent there can write.

What changes

  • Daemon (cmux-tui-core): agent-transfer-receive, agent-transfer-finish and agent-session-trust take a vm_kind param and use the same gate as agent-session-start:
    • On a Cloud VM they go on only on the exact vm_kind: "owner".
    • The VM's own record never counts.
    • Team evidence refuses even with the caller's word.
    • With no word they fail closed (agent_session.host_unverified).
    • Macs and SSH hosts need no word.
    • The old None path that took the record is gone: host_gate now takes a plain bool.
  • Page path: a page's routed agent_session.trust.get/set cannot vouch for the Cloud API's answer. It takes no vm_kind (bad_request), so it reaches no Cloud VM's trust.
  • Capabilities: new agent-transfer-vm-kind-v1 and agent-session-trust-vm-kind-v1.
  • Pump (cmux link agent move --vm-kind KIND):
    • Sends the kind on the receive and the finish to a target that serves the capability.
    • The flag is also the caller's word that the target is a Cloud machine. An older target would still trust its own record, so the pump refuses any kind but owner there (host_unverified, side: target) before the chat freezes. What the target advertises (fs-v1 or not) never changes that, because a guest can hide any sign of being a Cloud VM.
    • Without the flag the caller says the target is not a Cloud machine (Bring Back Local's Mac). A current Cloud daemon still refuses a chat with no word.
  • App:
    • Move to Cloud passes --vm-kind owner|none from the running link's answer, read at the move and never kept. The owner word names the link process it came from: --to-pid is CloudMachineLink.ownerPID. The pump sends the receive and the finish only over a connection whose peer is that process (SO_PEERCRED / LOCAL_PEERPID, via cmux_link::caller::peer_pid, now pub). So a link that restarts while the source's begin is pending never receives the old link's answer. Because the socket path stays the same, a rerun still resolves an unresolved move.
    • Remote folder trust takes the start's rule from Cloud link: the attested vmKind decides the VM boundary and app-started chats (owner only) #26323's review fix (8fa90e61b79). The app reads the link's owner answer (CloudMachineLink.ownerLink, a per-link id) before the connection and again as it sends. A Cloud machine's trust is refused without that answer, through any daemon. vm_kind: "owner" goes only to a daemon whose own identify on that connection lists agent-session-trust-vm-kind-v1.
  • Daemon gate: a vm_kind other than owner is refused (host_unverified) on any host for start, move-in and trust, because a guest's root can remove every Cloud sign the daemon reads.
  • Not changed: MDM's refusals. Nothing here loosens any check; on a Cloud VM every path only gets stricter.

Risk

Tests (cmux-ci, Linux)

  • Head b45560da004 (on Cloud link: the attested vmKind decides the VM boundary and app-started chats (owner only) #26323's 8ad048a1e9c), run https://github.com/manaflow-ai/cmux/actions/runs/40590890295: green. An explicit "vm_kind": null refuses on trust, receive and finish, as on start (present_nullable). Tested on a host with no Cloud sign: a_word_that_is_not_owner_refuses_on_any_host and the trust test. Clippy ran without the collapsible_if allowance, because the tip has the fix. Earlier heads, all green: 73a5f87134a (run 40589090968), fb6883a2fd1 (run 40586211848), d5506bb1052 (run 40583784546), 40d8fa0661c (run 40570069438), 7af51f7ed48 (run 40563544239), c0b87266ae7 (run 40558028188).
  • Base (Cloud link: the attested vmKind decides the VM boundary and app-started chats (owner only) #26323's head plus only the three new tests), run https://github.com/manaflow-ai/cmux/actions/runs/40558019316: each new test fails.
    • a_cloud_vm_takes_a_chat_only_on_the_callers_owner_word: a receive with no word succeeded on the owner record.
    • agent_session_trust_on_a_cloud_vm_needs_the_callers_owner_word: a trust read with no word succeeded.
    • the_cloud_apis_kind_reaches_the_target_or_an_older_one_is_refused: the pump has no --vm-kind. At the head this test also covers an older target that advertises nothing Cloud-like, given --vm-kind team or none: it is refused before agent-transfer-begin.
  • New at the head:
    • link_agent_move::the_owner_word_reaches_only_the_link_process_it_came_from: with another process at the socket, the pump sends no receive and no vm_kind, and the chat is given back. With the same process, the chat moves with owner.
    • CloudLinkReconnectingTests.theOwnerWordNamesTheLinkProcessItCameFrom (Swift): ownerPID is the link's pid, nil once the link ends, and the replacement's own pid after that.
  • Updated: cloud_move_journey and machine_update_journey now pass --vm-kind owner / vm_kind. The journey also checks that the bare and team forms are refused.
  • Swift: AgentSessionStartOwnerLinkTests.aCloudTrustCallGoesOutOnlyOnTheOwnerAnswerOfTheSameLink (real line socket); CloudMoveTests now expects --vm-kind none with no owner link. Compiled by PR CI only.

No capture: nothing visible changes. The Swift edits only decide whether --vm-kind owner / vm_kind is sent for Move to Cloud and remote folder trust. A refusal shows through the existing agent_session.host_unverified strings, and a fleet capture mini has no live owned Cloud link to show either path.

Agent session: agent session

🤖 Generated with Claude Code

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Owned by an agent session · session

@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 force-pushed the hb-acpmux/vm-boundary-link branch from 7989fd8 to da01839 Compare October 27, 2026 21:02
@teamleaderleo
teamleaderleo force-pushed the hb-acpmux/vm-kind-move-trust branch from 40d8fa0 to d5506bb Compare October 27, 2026 21:05
teamleaderleo added a commit that referenced this pull request Oct 27, 2026
… --vm-kind is left out

Review of #26330: with no --vm-kind the pump sent no word, so an older Cloud
daemon (no agent-transfer-vm-kind-v1) took the chat on its own record. Now an
older target that serves fs-v1 (only a Cloud host does), or does not answer
identify, is refused before the chat freezes unless the kind is owner. An older
Mac or SSH target still needs none (Bring Back Local).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-1288bbb2b5d2f5c6b66a
@teamleaderleo
teamleaderleo force-pushed the hb-acpmux/vm-kind-move-trust branch 2 times, most recently from 818574c to 73a5f87 Compare October 27, 2026 21:42
Base automatically changed from hb-acpmux/vm-boundary-link to feat-cmux-next October 27, 2026 22:08
@teamleaderleo
teamleaderleo force-pushed the hb-acpmux/vm-kind-move-trust branch from b45560d to 21a8721 Compare October 27, 2026 22:09
@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.

@github-actions

github-actions Bot commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

cmux status (one comment, edited in place; each line is updated by the job that owns it)

Review e9aed30: HQ feed card · gallery before/after runs · checks

App of this head (app.zip, kept 1 day)

gh workflow run reload-build.yml -R manaflow-ai/cmux --ref feat-cmux-next -f tag=pr26330 -f ref=hb-acpmux/vm-kind-move-trust -f platform=macos -f backend_mode=local

@github-actions github-actions Bot added the risk:normal Risk tier (docs/ci/risk-tiers.md) label Oct 27, 2026
@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Bead cx-utv35k created for this PR by the cmux coordinator.

@blacksmith-sh

blacksmith-sh Bot commented Oct 27, 2026 •

Copy link
Copy Markdown

Found 7 test failures on Blacksmith runners:

Failures

Test View Logs
main.WiringTests.test_both_deferrals_ask_the_script/
test_both_deferrals_ask_the_script
View Logs
main.WiringTests.test_the_pool_matches_the_daemon_test_job/
test_the_pool_matches_the_daemon_test_job
View Logs
build_only must be a conjunctive exclusion on the helper, signing, and publication jobs
, and must not gate the unsigned app build/
build_only must be a conjunctive exclusion on the helper, signing, and publication jobs
, and must not gate the unsigned app build
View Logs
nightly.yml must derive the embedded key and sign every appcast through the helper/
nightly.yml must derive the embedded key and sign every appcast through the helper
View Logs
test_the_nightly_is_covered (main.NightlyStepCoverageTests.test_the_nightly_is_cove
red)/
test_the_nightly_is_covered (main.NightlyStepCoverageTests.test_the_nightly_is_cove
red)
View Logs
test_the_repository_highlights_validate (main.DigestTests.test_the_repository_highl
ights_validate)/
test_the_repository_highlights_validate (main.DigestTests.test_the_repository_highl
ights_validate)
View Logs
unittest.case.FunctionTestCase (test_cmux_next_daemon_tests_take_blacksmith_linux_and_t
he_mac_shadow_never_the_promote_pool)/
unittest.case.FunctionTestCase (test_cmux_next_daemon_tests_take_blacksmith_linux_and_t
he_mac_shadow_never_the_promote_pool)
View Logs

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

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Review (codex gpt-6-astra xhigh, next-review): SHIP at dd29116

No blocking findings.

teamleaderleo and others added 3 commits October 27, 2026 16:49
…ner, never the VM's record

agent-transfer-receive, agent-transfer-finish and agent-session-trust take
vm_kind (agent-transfer-vm-kind-v1, agent-session-trust-vm-kind-v1) and use
the start's gate: on a Cloud VM they go on only on the caller's exact
"owner", team evidence refuses, no word fails closed, and any non-owner
word refuses on any host. A page's routed trust cannot vouch for it.

cmux link agent move --vm-kind KIND is the caller's word that the target
is a Cloud machine: sent on receive and finish to a daemon that takes it,
and against an older one any kind but owner is refused before the chat
freezes. --to-pid binds the owner word to the Cloud link process it came
from (peer pid on the receive/finish connection).

The app: Move to Cloud passes --vm-kind owner --to-pid from the running
link (CloudMachineLink.ownerPID), else none; remote folder trust uses the
start's owner-link check on the connection it was checked for.

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

agent-session-trust, agent-transfer-receive and agent-transfer-finish
decode vm_kind with present_nullable, as agent-session-start does, so an
explicit null is a word that is not owner and refuses on any host.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-1288bbb2b5d2f5c6b66a
@teamleaderleo
teamleaderleo force-pushed the hb-acpmux/vm-kind-move-trust branch from dd29116 to e9aed30 Compare October 27, 2026 23:49
@teamleaderleo
teamleaderleo merged commit e66cdf0 into feat-cmux-next Oct 28, 2026
192 of 198 checks passed
@teamleaderleo
teamleaderleo deleted the hb-acpmux/vm-kind-move-trust branch October 28, 2026 00:50
@github-actions

Copy link
Copy Markdown
Contributor

The feat-cmux-next push run https://github.com/manaflow-ai/cmux/actions/runs/40612539484 at 132b34c failed: cmux-next checks (god files, concurrency, crash safety, l10n).
Those jobs last passed at 676c2a3. This pull request is one of 2 merged since: #26330, #26443.
If the failure is in your change, fix forward on feat-cmux-next. Pull requests run only the tiers their paths reach (docs/ci/cmux-next-tiers.md); label a batch PR full-ci to run them all before merging.

@github-actions

github-actions Bot commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

This branch was previously deployed

3 inactive deployments
artifacts — e9aed304 Deployed Oct 28, 2026 by teamleaderleo via add the Windows daemon to the tree #67914
sentry-dsyms — e9aed304 Deployed Oct 28, 2026 by teamleaderleo via upload cmux-tui dSYMs to Sentry #67914
ci-routing-agent — e9aed304 Deployed Oct 27, 2026 by teamleaderleo via wait for same-key tree publisher #67914
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

risk:normal Risk tier (docs/ci/risk-tiers.md)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant