Skip to content

(remote): check a host's enrolment state from Settings (#222) - #429

Merged
devsuitup merged 2 commits into
mainfrom
feat/222-enrolment
Oct 3, 2026
Merged

devsuitup merged 2 commits into
mainfrom
feat/222-enrolment

Conversation

@devsuitup

@devsuitup devsuitup commented Oct 3, 2026 •

Copy link
Copy Markdown
Owner

What

Each host row in Settings gets a Check host button. One read-only ssh reports a checklist: ssh reachable, claude present (with its version), tmux or none, ~/.claude present, account logged in. For every missing or unknown item it shows the command to run, where to run it (on the host, or on this machine for ssh) and a Copy button. This is the Enrolment half of #222 (Launch was #427).

It reports state and acquires nothing. The check does not install, log in or write anything itself, and no credential is read, copied, hashed or tested.

The logged-in signal

claude auth status exits 0 when logged in and 1 when not (checked against CLI 2.1.288 locally, including with an empty CLAUDE_CONFIG_DIR). It prints the email and organisation, so the check runs it with stdout and stderr discarded and keeps only the exit status. The credentials file is never opened, and its existence is not tested either. Any other result gives unknown — run \claude` on the host once to log in`, never "logged out":

  • exit status other than 0 or 1;
  • claude auth --help without a status line (older CLI);
  • claude missing;
  • no ~/.claude (then claude auth status is not run at all, so the check does not create the host's config files).

How

  • ENROL_COMMAND is PROBE_COMMAND plus fixed text. PROBE_COMMAND and LIST_COMMAND are unchanged and stay pinned. No interpolation: the alias is the ssh operand, checked with isValidAlias and required to be in the saved remoteHosts.
  • parseEnrol is strict: the six lines in order or null. The version is the only free text and is kept only if it looks like a version. 2 KiB output cap, 30 s timeout, same run() and ssh options, so no new spawn site.
  • checkHost: ssh exit 255, spawn failure or timeout is unreachable; any other failure (a Windows host) is reachable with every other item unknown.
  • The panel builds its DOM with textContent only. Copy uses the main-process clipboard IPC.

Tests

  • test/remote-transport-enrol.test.js: command pin, negative match for anything credential-like, strict parse, checkHost outcomes, and a real sh with a stubbed claude (only auth status is ever run, never without ~/.claude).
  • test/remote-enrol.test.js: checklist per state, request guards, one check per host at a time.
  • test/dom-remote-enrol-panel.test.js: statuses, commands and copy, hostile text stays text, button flow.
  • test/main-remote-enrol-wiring.test.js: IPC checks the saved settings, preload, script tag.

Mutations (each turned a test red, then restored): auth output not discarded, extra lines accepted, version unchecked, size-cap check removed, exit 255 as reachable, exit 1 not mapped, no ~/.claude guard, no auth subcommand guard, undeclared alias accepted, invalid alias accepted, second concurrent check accepted, unknown auth shown as missing, unreachable host leaving items ok, detail and command via innerHTML, alias untrimmed, main's declared-host check removed. The fake claude now also writes the account details to stderr, and a separate test covers a CLI whose auth --help has no status line; dropping 2>&1 and dropping the grep status guard each fail a real-shell behaviour test as well as the string pin. The install hint now says to inspect the script first. A duplicate size-cap check in checkHost was removed. One mutation survived (a re-entry guard on the button, redundant with disabled), so the guard was removed.

Not verified

  • Whether claude auth status itself refreshes or rewrites an expired token, or makes network calls, on the host. Switchboard only receives the exit status.
  • A real host: tests use a fake spawn and a real sh.
  • claude auth login or claude setup-token on a machine with no browser. The checklist hands claude auth login; both subcommands exist in --help, but their headless behaviour was not run.
  • The install one-liner and sudo apt install tmux are assumptions about the host, shown as text only.
  • A login that exists only through an environment variable of an interactive profile reads as not logged in in the non-interactive check.

Linux hosts with a POSIX login shell only: a Windows host, or a fish/csh login shell, is reported as not checked with that cause named (the command is not wrapped in sh -c, so the probe prefix pin holds). Only tmux is looked for.

Closes #222

Each host row gets a Check host button: one read-only ssh reports ssh,
the claude CLI and version, tmux, ~/.claude and the login, and hands the
command to run on the host for each missing item. Login is read from the
exit status of `claude auth status`, whose output is discarded; no
credential is read or copied.

Closes #222
@devsuitup

Copy link
Copy Markdown
Owner Author

Reviewing 8c2b6e4 (adversarial review in progress).

@devsuitup devsuitup left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Adversarial review at 8c2b6e4: 0 blocking. claude auth status runs with stdout, stderr and stdin discarded, and only its exit status is echoed. The version is capped at 64 bytes and checked by a regex. Nothing logs raw ssh output, and the credentials file is never referenced. ENROL_COMMAND is constant, and the alias is validated and must be saved. The parse is strict (a banner, extra lines or ANSI all give "unexpected output"). The renderer uses textContent only. Being fixed: the docs claim a read-only check, but whether auth status refreshes an expired token is unverified. Also being fixed: the message shown on a non-POSIX login shell, two test gaps (stderr not exercised, older-CLI guard mutation survives) and a dead check.

Say what is not known about `claude auth status` (it may refresh a token
or touch the network on the host), name a non-POSIX login shell as a
cause of an unreadable check, and tell the reader to inspect the install
script first. The fake claude now also prints its account details to
stderr, and an older CLI without an `auth status` line has its own test,
so dropping `2>&1` or the status guard fails a behaviour test. Remove a
duplicated size-cap check.

Refs #222

@devsuitup devsuitup left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Re-review at f81e513 (delta from 8c2b6e4), pushed as f81e513: 0 blocking. The docs say "does not install, log in or write anything itself", and list token refresh by auth status as not verified. The no-facts detail names the POSIX-shell requirement. The fake claude now writes to stderr too: dropping 2>&1 fails a behaviour test. The older-CLI guard has its own test, killed by mutation. The dead check is removed and the install hint says to inspect the script.

@devsuitup
devsuitup merged commit 9eb6435 into main Oct 3, 2026
11 checks passed
@devsuitup
devsuitup deleted the feat/222-enrolment branch October 3, 2026 09:55
@devsuitup devsuitup mentioned this pull request Oct 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

design(remote): launch a session on a host, and enrol the host

1 participant