remove-host: --retain on --finish is ignored, and a connected hand-joined host reads "unreachable" / "setup didn't install" #412

Open
opened 2026-11-06 22:47:08 +00:00 by kayg · 0 comments
Owner

Found by J216b during the D356 real-root proof (#355, comments 82641 / 83166). Not fixed on the D356 branches.

What the person sees

remove-host <host> --server <origin> --finish --retain --json on a hand-joined host (infraternal agent join, not infraternal setup) that is connected answered:

{"schema_version":1,"command":"remove-host","ok":true,"state":"pending","message":"2d7a3ddaabbb47918104a50dbf9cb5a1: revoked, cleanup pending; infraternal setup didn't install its infraternal agent, so remove it there the way it was installed.","next":[],"data":{"access_report":{"host_id":"2d7a3dda-abbb-4791-8104-a50dbf9cb5a1","reports":[],"state":"pending"},"host_cleanup":"unreachable","host_id":"2d7a3dda-abbb-4791-8104-a50dbf9cb5a1","manual":null,"message":"…same…","state":"pending"}}

The person asked to keep the infraternal agent (--retain), yet the result:

  • says nothing about keeping it;
  • reports host_cleanup: "unreachable" for a host that was connected at the time;
  • tells them to remove the agent by hand.

Why, from the code (dev as of 821b55cc6, unchanged on the D356 branches)

  1. The CLI ignores --retain on --finish.
    • crates/infraternal/src/host_remove.rs: only the dry run sends the choice (Step::Start => {"host_id", "uninstall": !retain}). The finish sends {"host_id", "review"}.
    • The server takes uninstall from the dry run's pending review (remote_removal.rs, Pending.uninstall).
    • So --retain on --finish is accepted and silently has no effect. Unless the dry run had --retain, the removal requests an uninstall.
  2. "unreachable" covers a refusal too. In remote_removal.rs request_uninstall, every reply other than {"state":"accepted"} (a missing actor, a failed call, or a refusal) becomes "unreachable". A hand-joined host has no setup installation, so its uninstall does not accept, and a connected host is reported as unreachable.
  3. The wording. outcome(...) with pending and installation == None (not installed by setup) then picks "infraternal setup didn't install its infraternal agent, so remove it there the way it was installed". That is true about the installation, but it answers a question the person did not ask.

Reproduce

Any of these works:

  • The live proof test. Run runtime::remote_demo_tests::access_report_live::access_report_reaches_remove_host_through_a_live_server on revoke-access-report-d356b as root through a root clone. It calls the dry run without --retain and then --finish --retain; the message is printed as REMOVE_HOST_FINISH.
  • By hand. Join a host with infraternal agent join <origin>/remote/join (not setup). Then run remove-host <host> --server <origin> --json (the dry run, without --retain), then remove-host <host> --server <origin> --finish --retain --json with the review on stdin.
  • Compare. Pass --retain on the dry run instead: host_cleanup is then "retained" and the message reads "its infraternal agent stays installed on it".

Open choices (owner or implementer; I did not decide them)

  • Fix --retain on --finish. Either refuse it on --finish (the choice belongs to the dry run, which its review binds), or show what the review chose.
  • Separate the cases. Tell "the host refused or could not run an uninstall" apart from "the host is unreachable" in host_cleanup, and word each one.
Found by J216b during the D356 real-root proof (#355, comments 82641 / 83166). **Not fixed on the D356 branches.** ## What the person sees `remove-host <host> --server <origin> --finish --retain --json` on a hand-joined host (`infraternal agent join`, not infraternal setup) that is connected answered: ``` {"schema_version":1,"command":"remove-host","ok":true,"state":"pending","message":"2d7a3ddaabbb47918104a50dbf9cb5a1: revoked, cleanup pending; infraternal setup didn't install its infraternal agent, so remove it there the way it was installed.","next":[],"data":{"access_report":{"host_id":"2d7a3dda-abbb-4791-8104-a50dbf9cb5a1","reports":[],"state":"pending"},"host_cleanup":"unreachable","host_id":"2d7a3dda-abbb-4791-8104-a50dbf9cb5a1","manual":null,"message":"…same…","state":"pending"}} ``` The person asked to keep the infraternal agent (`--retain`), yet the result: - says nothing about keeping it; - reports `host_cleanup: "unreachable"` for a host that was connected at the time; - tells them to remove the agent by hand. ## Why, from the code (dev as of 821b55cc6, unchanged on the D356 branches) 1. **The CLI ignores `--retain` on `--finish`.** - `crates/infraternal/src/host_remove.rs`: only the dry run sends the choice (`Step::Start => {"host_id", "uninstall": !retain}`). The finish sends `{"host_id", "review"}`. - The server takes `uninstall` from the dry run's pending review (`remote_removal.rs`, `Pending.uninstall`). - So `--retain` on `--finish` is accepted and silently has no effect. Unless the dry run had `--retain`, the removal requests an uninstall. 2. **"unreachable" covers a refusal too.** In `remote_removal.rs` `request_uninstall`, every reply other than `{"state":"accepted"}` (a missing actor, a failed call, or a refusal) becomes `"unreachable"`. A hand-joined host has no setup installation, so its uninstall does not accept, and a connected host is reported as unreachable. 3. **The wording.** `outcome(...)` with `pending` and `installation == None` (not installed by setup) then picks "infraternal setup didn't install its infraternal agent, so remove it there the way it was installed". That is true about the installation, but it answers a question the person did not ask. ## Reproduce Any of these works: - **The live proof test.** Run `runtime::remote_demo_tests::access_report_live::access_report_reaches_remove_host_through_a_live_server` on `revoke-access-report-d356b` as root through a root clone. It calls the dry run without `--retain` and then `--finish --retain`; the message is printed as `REMOVE_HOST_FINISH`. - **By hand.** Join a host with `infraternal agent join <origin>/remote/join` (not setup). Then run `remove-host <host> --server <origin> --json` (the dry run, without `--retain`), then `remove-host <host> --server <origin> --finish --retain --json` with the review on stdin. - **Compare.** Pass `--retain` on the dry run instead: `host_cleanup` is then `"retained"` and the message reads "its infraternal agent stays installed on it". ## Open choices (owner or implementer; I did not decide them) - **Fix `--retain` on `--finish`.** Either refuse it on `--finish` (the choice belongs to the dry run, which its review binds), or show what the review chose. - **Separate the cases.** Tell "the host refused or could not run an uninstall" apart from "the host is unreachable" in `host_cleanup`, and word each one.
Sign in to join this conversation.
No labels
launch-qa
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
kayg/infraternal#412
No description provided.