Skip to main content

systemprompt_cli/commands/admin/
mod.rs

1//! `admin` command tree: privileged platform administration.
2//!
3//! [`AdminCommands`] groups user, agent, configuration, session, bridge,
4//! access-control, and signing-key management plus the setup and bootstrap
5//! flows. On a `--database-url` invocation only the user-management subgroup
6//! is served; the rest require a full profile context.
7//!
8//! Copyright (c) systemprompt.io — Business Source License 1.1.
9//! See <https://systemprompt.io> for licensing details.
10
11pub mod access_control;
12pub mod agents;
13pub mod bootstrap;
14pub mod bridge;
15pub mod config;
16pub mod identity;
17pub mod keys;
18pub mod session;
19pub mod setup;
20pub mod users;
21
22use anyhow::Result;
23use clap::Subcommand;
24
25use crate::context::CommandContext;
26use crate::shared::render_result;
27
28#[derive(Debug, Subcommand)]
29pub enum AdminCommands {
30    #[command(subcommand, about = "User management and IP banning")]
31    Users(users::UsersCommands),
32
33    #[command(subcommand, about = "Agent management")]
34    Agents(agents::AgentsCommands),
35
36    #[command(subcommand, about = "Configuration management and rate limits")]
37    Config(config::ConfigCommands),
38
39    #[command(about = "Interactive setup wizard for local development environment")]
40    Setup(setup::SetupArgs),
41
42    #[command(
43        about = "Idempotently ensure the system admin user exists with the admin role. Required \
44                 by every install recipe before services start. Note: the admin ROLE only — \
45                 deployments that derive platform admin from organization membership grant that \
46                 half themselves (at boot, or via their own tooling)."
47    )]
48    Bootstrap(bootstrap::BootstrapArgs),
49
50    #[command(subcommand, about = "Manage CLI session and profile switching")]
51    Session(session::SessionCommands),
52
53    #[command(
54        subcommand,
55        about = "Bridge helper enrollment (device certs, exchange codes)"
56    )]
57    Bridge(bridge::BridgeCommands),
58
59    #[command(
60        subcommand,
61        name = "access-control",
62        about = "Access-control baseline operations (DB → YAML export)"
63    )]
64    AccessControl(access_control::AccessControlCommands),
65
66    #[command(
67        subcommand,
68        about = "RSA signing-key generation for the federated JWT plane"
69    )]
70    Keys(keys::KeysCommands),
71
72    #[command(
73        subcommand,
74        about = "Replica identity secrets shared by every node of a deployment"
75    )]
76    Identity(identity::IdentityCommands),
77}
78
79pub async fn execute(cmd: AdminCommands, ctx: &CommandContext) -> Result<()> {
80    if ctx.is_database_scoped()
81        && !matches!(cmd, AdminCommands::Users(_) | AdminCommands::Session(_))
82    {
83        return Err(crate::shared::database_scoped_command_error());
84    }
85
86    match cmd {
87        AdminCommands::Users(cmd) => users::execute(cmd, ctx).await,
88        AdminCommands::Agents(cmd) => Box::pin(agents::execute(cmd, ctx)).await,
89        AdminCommands::Config(cmd) => config::execute(cmd, ctx).await,
90        AdminCommands::Setup(args) => {
91            let result = Box::pin(setup::execute(args, ctx)).await?;
92            render_result(&result, &ctx.cli);
93            Ok(())
94        },
95        AdminCommands::Bootstrap(args) => {
96            let result = bootstrap::execute(args, &ctx.cli).await?;
97            render_result(&result, &ctx.cli);
98            Ok(())
99        },
100        AdminCommands::Session(cmd) => session::execute(cmd, ctx).await,
101        AdminCommands::Bridge(cmd) => bridge::execute(cmd, ctx).await,
102        AdminCommands::AccessControl(cmd) => access_control::execute(cmd, ctx).await,
103        AdminCommands::Keys(cmd) => keys::execute(cmd, ctx).await,
104        AdminCommands::Identity(cmd) => identity::execute(cmd, ctx),
105    }
106}