Skip to content

acpmux: host approvals, and host enroll enrolls this Mac's app key on the machine (peer-route approvals 2/4) - #26133

Merged
teamleaderleo merged 3 commits into
feat-cmux-nextfrom
lane/hb-peer-approvals-cli
Oct 27, 2026
Merged

teamleaderleo merged 3 commits into
feat-cmux-nextfrom
lane/hb-peer-approvals-cli

Conversation

@teamleaderleo

@teamleaderleo teamleaderleo commented Oct 27, 2026 •

Copy link
Copy Markdown
Collaborator

Peer-route approvals, part 2 of 4: enroll this Mac's app key on a peer. Part 1 (#26131) has landed; this PR is on feat-cmux-next.

Part 1 lets a peer count an Allow signed by a Mac listed in its mac-approvers.json. This PR adds the commands that put the Mac in that file, plus the name a refusal needs for the card's hint.

  • acpmux host approvals lists the Macs that may allow this machine's prompts, and this machine's own app key (thisMac).
    • host approvals add --id ID --key HEX --name NAME and host approvals rm ID change the file under a lock. The file is rewritten whole with 0600 permissions.
    • After each change the command makes the daemon reload (part 1's reload), so a removal stops that Mac's Allows at once. The file's lock is held until that reload returns, so a concurrent add cannot land between rm's write and its reload. A running daemon that does not reload fails the command (and so a remote enroll/unenroll).
  • host approvals enroll PEER / unenroll PEER, run on the Mac:
    • reads this Mac's app key from the local daemon (_acpmux/mac_approvers thisMac, which the app sets in part 3);
    • runs host approvals add / rm on that peer over ssh, with the same ssh route host enroll uses.
  • acpmux host enroll and host doctor gain an approvals step. It is the same check:
    • ok when the Mac is enrolled with the same key fingerprint;
    • warn with "fix: acpmux host doctor NAME --fix" when it is not;
    • fixed after --fix or enroll;
    • skip when no cmux app has given a key ("open cmux on this Mac");
    • warn "too old" with acpmux host update NAME when the remote acpmux has no host approvals.
    • The Swift HostStep already tolerates unknown steps.
  • permission_respond refused by a peer now carries data.peer, the local daemon's name for that peer, unless the error names one already. The app uses it for the "enroll this Mac on HOST" hint (parts 3 and 4).

Conditions

  • (4) Unenrolling stops Allows at once: host approvals rm, and unenroll from the Mac, rewrite the file and then reload under the set's lock (part 1), holding the file's lock until the reload returns; a reload that fails fails the command.
  • (5) No private key moves: only the public key and its id cross ssh. No RPC adds a key; add writes the peer's file as the ssh user.

Tests (they fail before the fix and pass after)

They ran remotely through cmux-ci test.

Before: the enroll step taken out, and no peer name on a refusal.

test server::peer_forward::tests::a_refused_answer_names_the_peer ... FAILED
test cli::host_approvals::tests::enroll_adds_this_macs_app_key_once_and_doctor_finds_it ... FAILED

Before (review round): the lock let go before the reload, and a reload failure ignored.

test cli::host_approvals::tests::a_daemon_that_does_not_reload_fails_the_change ... FAILED
test cli::host_approvals::tests::a_change_holds_its_lock_until_the_reload_returns ... FAILED

After:

test cli::host_approvals::tests::no_app_key_skips_and_an_old_remote_warns_with_the_update ... ok
test cli::host_approvals::tests::enroll_adds_this_macs_app_key_once_and_doctor_finds_it ... ok
test server::peer_forward::tests::a_refused_answer_names_the_peer ... ok
test cli::host_approvals::tests::a_change_rewrites_the_file_whole_and_keeps_each_mac_once ... ok
test cli::host_approvals::tests::a_change_holds_its_lock_until_the_reload_returns ... ok
test cli::host_approvals::tests::a_daemon_that_does_not_reload_fails_the_change ... ok
lib (filtered, review round): 46 passed; clippy -D warnings and fmt --check clean
lib (filtered): 56 passed; peer_integration: 49 passed; person_allow: 25 passed; clippy -D warnings clean

No capture: CLI and daemon only, with no app or webview change. Part 3 carries the card captures.

Overlap: #25822 (an update step in host enroll) changes the same step list. Whichever lands second rebases.

Agent session: agent session

🤖 Generated with Claude Code

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Owned by an agent session · session

@teamleaderleo teamleaderleo changed the title acpmux: host approvals, and host enroll enrolls this Mac's app key on the machine (peer-route approvals 2/3) acpmux: host approvals, and host enroll enrolls this Mac's app key on the machine (peer-route approvals 2/4) Oct 27, 2026
Base automatically changed from lane/hb-peer-approvals-daemon to feat-cmux-next October 27, 2026 11:07
… the machine (peer-route approvals 2/4)

acpmux host approvals [add|rm] keeps the Macs whose app may allow this
machine's prompts (ACPMUX_HOME/mac-approvers.json, a locked
read-modify-write and one rename), then has the running daemon reload, so rm
stops a Mac's Allows once it returns. host enroll and host doctor get an
approvals step: this machine's app key (the local daemon's
_acpmux/mac_approvers thisMac) is added on the machine over ssh with --fix;
no app key skips, an old remote warns with host update. Never a failure.

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 lane/hb-peer-approvals-cli branch from 9a4b956 to cf385b5 Compare October 27, 2026 11:08
@github-actions github-actions Bot added the risk:normal Risk tier (docs/ci/risk-tiers.md) label Oct 27, 2026
@blacksmith-sh

blacksmith-sh Bot commented Oct 27, 2026 •

Copy link
Copy Markdown

Found 7 test failures on Blacksmith runners:

Failures

Test View Logs
/tmp/tmpjm607jdk/summary-fail.json (live):/summary-fail.json (live): View Logs
/tmp/tmpzg8_b5zu/summary-missing.json (live):/summary-missing.json (live): View Logs
[new_workspaces] debug.new_workspace timed 0 of 50 new workspace rows/
[new_workspaces] debug.new_workspace timed 0 of 50 new workspace rows
View Logs
[new_workspaces] the window draws no frames/[new_workspaces] the window draws no frames View Logs
[tabs] debug.tab_switch timed 0 of 40 switches/
[tabs] debug.tab_switch timed 0 of 40 switches
View Logs
[tabs] the window draws no frames/[tabs] the window draws no frames View Logs
convention violations found (ERROR lines above)./
convention violations found (ERROR lines above).
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

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

@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 0bee346: 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=pr26133 -f ref=lane/hb-peer-approvals-cli -f platform=macos -f backend_mode=local

red: cmux-next checks (god files, concurrency, crash safety, l10n); no finished base run on 5c79c71 to compare; do not merge until green; see lane-rules

…oad, and a reload that fails fails the change

Review of #26133: a concurrent add could land between rm's write and its
reload and put back the key rm took out, and a running daemon that did not
reload was reported as success with reloaded: false.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-1288bbb2b5d2f5c6b66a
…provals change, and a refusal names only this daemon's peer

Review of #26133: reload() read every connect error as "no daemon"; it now
checks daemon.lock and fails the change when a daemon holds it. A peer's own
data.peer on a refused answer is replaced by this daemon's name for that
peer, so the app's Enroll button never targets a host the peer named.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-1288bbb2b5d2f5c6b66a
@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

This branch had an error being deployed

1 failed and 2 inactive deployments
artifacts — 0bee3467 Deployed Oct 27, 2026 by teamleaderleo via publish the Windows daemon to R2 #64689
sentry-dsyms — 0bee3467 Deployed Oct 27, 2026 by teamleaderleo via upload cmux-tui dSYMs to Sentry #64689
ci-routing-agent — 0bee3467 Deployed Oct 27, 2026 by teamleaderleo via wait for same-key tree publisher #64689
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