Skip to content

Stop Connect daemons before revocation - #859

Merged
hamzamerzic merged 1 commit into
mobius-os:mainfrom
hamzamerzic:fix/connect-daemon-disconnect
Aug 22, 2026
Merged

Stop Connect daemons before revocation#859
hamzamerzic merged 1 commit into
mobius-os:mainfrom
hamzamerzic:fix/connect-daemon-disconnect

Conversation

@hamzamerzic

Copy link
Copy Markdown
Collaborator

Summary

  • stop and uninstall an online Connect runner before revoking its machine token
  • keep offline removal explicit by showing the local uninstall command and requiring a deliberate server-only removal
  • support runners installed before the disconnect protocol while requiring their channel to close before revocation
  • remove service persistence, runner credentials, and fallback background processes
  • cover command dispatch, timeout cleanup, offline behavior, and disconnect failure paths

Follow-up to #854, which introduced secure external machine pairing.

Testing

  • 14 passed — focused Connect route and runner tests
  • 83 passed — backend host contract suite
  • Python compilation and diff checks passed

Co-authored-by: Möbius Agent <mobius-agent@users.noreply.github.com>
@hamzamerzic hamzamerzic added area: backend Server and API behavior bug Something isn't working labels Aug 22, 2026

@miljanm miljanm left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Reviewer: QA second look

I found the following concrete risks. I’ve kept this focused on issues with a supported failure mode rather than style preferences.

HIGH · force=true cannot revoke an online runner that refuses to acknowledge disconnect

backend/app/routes/connect.py:372 · security
Reviewer rule: security.authority_boundary

A compromised or merely malfunctioning runner that keeps its SSE stream open and either nacks the disconnect (exit_code!=0) or never closes gates the owner's revocation on its own cooperation. Every DELETE — including ?force=true — then fails and preserves the still-valid machine token, inverting the purpose of revocation for exactly the untrusted-machine case it exists to handle. The only owner-side recovery is restarting Möbius to clear in-memory _channels, since /disconnect requires the host's own bearer.

Evidence: In delete_host the new force flag is only consulted inside the if ch is None (offline) branch. When a channel exists the code always takes else: daemon = await _ask_runner_to_disconnect(ch), and that helper raises HTTPException 502 on a nonzero uninstall result or 504 when ch.closed never fires — both before _forget_host(host_id) runs. Tests test_failed_daemon_cleanup_keeps_the_connection (502) and test_unconfirmed_legacy_shutdown_keeps_the_connection (504) assert the host and channel are retained after failure.

Suggested direction: Have force=true bypass the online ack requirement: perform a best-effort disconnect on the online branch but still call _forget_host unconditionally when force is set, so the owner can always revoke a token even when a runner refuses to confirm shutdown.

Reviewed revision 599c33a1275b.

@hamzamerzic
hamzamerzic added this pull request to the merge queue Aug 22, 2026
Merged via the queue into mobius-os:main with commit ba308dd Aug 22, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: backend Server and API behavior bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants