feat(cli): add llmux user commands (create/list/delete/reset-passphrase)#81
Merged
Conversation
…ssphrase The sign-in page's footer has told locked-out operators to run `sudo llmux user reset-passphrase <username>` since v2 auth shipped. That command never existed — `llmux user` returned "unknown command". There was no CLI recovery path at all for a locked-out sole admin; the equivalent web endpoints (/api/admin/users) require already being signed in as an admin, which is exactly the thing you don't have if you're locked out. Added four verbs, mirroring the existing `token` CLI's pattern exactly (daemon/handlers.ts: direct filesystem access to the v2 store — no caller-identity concept, since shell access to the box IS the trust boundary, same reasoning as token create/list/revoke): - `user create <username> [--name N] [--admin] [--passphrase P]` — prompts for passphrase + confirmation if not given via flag/env - `user list [--json]` - `user delete <username> [--yes]` — refuses to delete the last admin (mirrors handleAdminDeleteUser's exact rule); revokes the user's tokens on delete - `user reset-passphrase <username> [--passphrase P]` — admin-style override, no old passphrase needed; revokes the user's existing tokens (matches handleAdminResetPassphrase's behavior) Also fixed the login page's footer note: it said `sudo llmux user reset-passphrase` — sudo is actively wrong here, not just unnecessary. The standard (user-mode) deployment stores v2 data under the daemon operator's own $XDG_DATA_HOME; running via sudo would resolve HOME to root's and silently operate on the wrong (nonexistent) store. Removed sudo, added a note not to use it. ## Verification typecheck + build clean. Live against the running daemon: - create/list/duplicate-username/bad-username/short-passphrase all produce clean, correct errors or output - minted a token for a test user, confirmed 200; reset-passphrase -> confirmed the old token now 401s (revocation works) - delete without --yes on a non-TTY correctly refuses; delete --yes removes the user and reports revoked-token count; delete of a nonexistent user errors cleanly - root --help renders the new verb block correctly The "refuses to delete the last admin" guard is a direct copy of the already-shipped, proven web logic (v2/auth/handlers.ts handleAdminDeleteUser) — not independently live-tested here, since doing so safely would require reducing this machine's real admin accounts (stevekrisjanovs, orchtest) to one, which isn't warranted for a test. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Au8T9RPCb6wbgiEecQrBfZ
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Found during the multi-pass sweep: the sign-in page's footer has told locked-out operators to run
sudo llmux user reset-passphrase <username>since v2 auth shipped — that command never existed. There was no CLI recovery path at all for a locked-out sole admin (the web/api/admin/usersendpoints require already being signed in as an admin).Adds four verbs, mirroring the existing
tokenCLI's pattern (direct filesystem access to the v2 store, no caller-identity concept — same trust model astoken create/list/revoke):user create <username> [--name N] [--admin] [--passphrase P]user list [--json]user delete <username> [--yes]— refuses to delete the last admin; revokes the user's tokensuser reset-passphrase <username> [--passphrase P]— admin-style override, revokes existing tokensAlso fixed the login footer's
sudo— it's actively wrong, not just unnecessary: the standard deployment stores v2 data under the daemon operator's own$XDG_DATA_HOME, andsudowould resolveHOMEto root's, silently pointing at the wrong store.Test plan
npm run typecheck/npm run buildclean200;reset-passphrase→ confirmed the old token now401sdeletewithout--yeson non-TTY refuses cleanly;delete --yesremoves + reports revoked-token count; delete of nonexistent user errors cleanly--helprenders the new verb block correctlyhandleAdminDeleteUserlogic), not live-repro'd — doing so safely would require reducing this machine's two real admin accounts to one🤖 Generated with Claude Code
https://claude.ai/code/session_01Au8T9RPCb6wbgiEecQrBfZ