swarmctl: add user list

This commit is contained in:
damocles 2026-08-17 18:50:27 +02:00
commit 0138b0e0ac
2 changed files with 45 additions and 0 deletions

View file

@ -8,6 +8,7 @@ This document contains the help content for the `swarmctl` command-line program.
* [`swarmctl user`↴](#swarmctl-user)
* [`swarmctl user add`↴](#swarmctl-user-add)
* [`swarmctl user update`↴](#swarmctl-user-update)
* [`swarmctl user list`↴](#swarmctl-user-list)
* [`swarmctl completions`↴](#swarmctl-completions)
## `swarmctl`
@ -41,6 +42,7 @@ Manage subjects in the swarm's SSO provider
* `add` — Add a user, generating a password for them
* `update` — Change an existing user's attributes
* `list` — List every user in the canonical store
@ -83,6 +85,16 @@ Every flag is optional and they compose, so one call can set several things at o
## `swarmctl user list`
List every user in the canonical store.
Reads `store` only — never authelia's rendered `users.yml`, which is a derived artifact this crate writes and never reads back (see the crate doc comment). One line per user: username, display name, email (if set), groups (if any).
**Usage:** `swarmctl user list`
## `swarmctl completions`
Generate a shell completion script for `swarmctl` and print it to stdout.

View file

@ -172,6 +172,13 @@ enum UserVerb {
/// editing an attribute, and folded together an attribute edit can
/// invalidate a login by accident.
Update(UpdateArgs),
/// List every user in the canonical store.
///
/// Reads `store` only — never authelia's rendered `users.yml`, which
/// is a derived artifact this crate writes and never reads back (see
/// the crate doc comment). One line per user: username, display name,
/// email (if set), groups (if any).
List,
}
#[derive(Args)]
@ -220,6 +227,9 @@ fn main() -> Result<()> {
Verb::User {
command: UserVerb::Update(args),
} => user_update(&paths.resolve()?, args),
Verb::User {
command: UserVerb::List,
} => user_list(&paths.resolve()?),
Verb::MarkdownDocs => {
print!("{}", clap_markdown::help_markdown::<Cli>());
Ok(())
@ -306,6 +316,29 @@ fn user_update(paths: &Paths, args: UpdateArgs) -> Result<()> {
Ok(())
}
/// `swarmctl user list` — read-only, never touches authelia's users file
/// or restarts it. Prints one line per user from the canonical store.
fn user_list(paths: &Paths) -> Result<()> {
use std::fmt::Write as _;
let store = load_store(&paths.store, &paths.users_file)?;
if store.users.is_empty() {
println!("no users in {}", paths.store.display());
return Ok(());
}
for (username, user) in &store.users {
let mut line = format!("{username}\t{}", user.displayname);
if let Some(email) = &user.email {
let _ = write!(line, "\t{email}");
}
if !user.groups.is_empty() {
let _ = write!(line, "\tgroups: {}", users::fmt_groups(&user.groups));
}
println!("{line}");
}
Ok(())
}
/// Write the store + the rendered users file, then restart authelia.
///
/// Shared by every verb that mutates the store, so the ordering rules