acpmux: the caller's side of the VM boundary (vmBoundary lease, saved peer, forwarding)
The caller's side of the VM boundary. A caller keeps its own opt-out for a peer's remote chains, and forwards it only for the person's own clients. No machine's behaviour changes yet: the guest ignores the field until #26276 (the guest's side) lands.
The design, as agreed with 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".
PR 2a of the series. The order:
- Done: fail-closed #26227 (every Cloud VM sandboxes).
- Done: web/ attach-endpoint
vmKind#26222 (live). - This PR (2a): the caller's side.
- #26276 (2b): the guest's side.
- (3): the Cloud link passes
--vm-kind ownerinto the lease, only when the Cloud API answered"owner"for the signed-in caller.
This was one PR. I split it to keep each part under about 800 lines.
What changes
-
Saved peer:
vmBoundary: trueon a saved peer in the caller's own config.json, for a VM its fleet registry calls a dedicated agent VM.peer_addnever sets it, and a re-add of the same name and URL keeps it. A config reload applies the file's value to the running peer (same URL only) with no reconnect. A leased peer keeps its lease's value. -
Cloud link lease:
_acpmux/peer_lease {vmBoundary: true}(unix socket only). PR 3's link sends it only when the Cloud API said this caller owns the VM. It is held with the lease and never saved. Only the JSON valuetruecounts. -
Forwarding: each
session/newthe caller forwards to such a peer carries_meta.acpmux.vmBoundary: true, but only for the person's own clients (vm_boundary::owner):- the unix socket;
- the app (
LocalApp); - the caller's own peer daemon asking for itself (
PeerTokenandControl::Peer).
It is never added for a Web client, the listener token, a paired machine (
Device,ReadOnlyDevice) or a request held to the Web's rules. AnyvmBoundarythe client sent itself is dropped first. -
via: device: a request this daemon forwards for a paired machine'sclientcredential, which is served as a peer, now saysvia: device. The peer then never takes it for the owner's. An older peer ignores the mark, and its folder-trust gate treats it as before (novia).
Risk
Low. Nothing reads the field on the guest yet. The lease takes one more optional param, and the forwarded session/new carries one more _meta key that older daemons ignore (vmBoundary is not a mode field).
Tests
tests/peer_lease.rs a_vm_boundary_lease_forwards_the_boundary_for_the_persons_own_clients_only uses a fake peer that records each forwarded session/new:
- With a
vmBoundarylease, the unix socket's and the app's starts carryvmBoundary: true. - With a plain lease, they don't, even though each client sent
vmBoundary: trueitself. - A Web client's or a paired machine's start never carries it. If either is forwarded at all, it goes as
via: weborvia: device.
a_reload_takes_a_saved_peers_vm_boundary_back checks that a reload turns a saved peer's boundary off and on again with no reconnect. Unit tests cover forwards and owner.
Before and after
On base 370fc6137dc, with only the new forwarding test:
test a_vm_boundary_lease_forwards_the_boundary_for_the_persons_own_clients_only ... FAILED
panicked at crates/acpmux/tests/peer_lease.rs:377:13:
left: Some(Bool(true))
right: None
test result: FAILED. 6 passed; 1 failed
On base, a plain lease forwards the client's own vmBoundary.
At this head (cmux-ci, Linux):
cargo fmt -p acpmux --check: ok
cargo clippy -p acpmux --all-targets -- -D warnings: ok (with the base's collapsible_if red in cli/codex_auth_broker.rs patched locally, not in this PR)
lib vm_boundary peer_lease peers catalog_reload remote_guard: 35 passed
--test peer_lease 8, web_token_exposure 6, peer_integration 50, remote_new_hints 8, peer_origin 4, pairing 7, local_app_origin 7: all passed
The full cargo test -p acpmux fails on the tip the same way it fails here: agent_tools, codex_auth_broker, daemon_chat_open, ephemeral_run, hermetic_daemon_guard and session_pool.
Agent session: agent session
š¤ Generated with Claude Code
![View with [code]smith](https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-dark-v3-3x.png)
![Autofix with [code]smith](https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark-3x.png)
Need help on this PR? Tag @codesmith-bot with what you need.
Summary by cubic
Implements the caller's side of the VM boundary: a caller marks a peer as a VM it owns, and its daemon forwards _meta.acpmux.vmBoundary: true on session/new for that peer. The mark comes from a saved peer's vmBoundary in config.json (a reload applies the file's value with no reconnect) or from _acpmux/peer_lease {vmBoundary: true}, which is held with the lease and never saved.
- The boundary is forwarded only for the person's own clients: the unix socket, the app, and the caller's own peer daemon. Web clients, paired machines, and listener-token connections never get it, and any
vmBoundarya client sends itself is dropped first. - Requests forwarded for a paired machine's client credential now carry
via: deviceso the peer never treats them as the owner's. - The guest ignores the field until the next PR lands, so no behavior changes yet.