systemprompt-cli 0.3.0

Unified CLI for systemprompt.io AI governance: agent orchestration, MCP governance, analytics, profiles, cloud deploy, and self-hosted operations.
Documentation
use anyhow::{Result, anyhow};
use clap::Args;
use systemprompt_identifiers::UserId;
use systemprompt_runtime::AppContext;
use systemprompt_users::{DeviceCertService, EnrollDeviceCertServiceParams};

use super::types::DeviceCertEnrolledOutput;
use crate::CliConfig;
use crate::shared::CommandResult;

#[derive(Debug, Args)]
pub struct EnrollCertArgs {
    #[arg(long, help = "User ID to enroll the cert for")]
    pub user_id: String,

    #[arg(long, help = "SHA-256 fingerprint of the device certificate (hex)")]
    pub fingerprint: String,

    #[arg(
        long,
        help = "Human-readable label for the cert",
        default_value = "device"
    )]
    pub label: String,
}

pub async fn execute(
    args: EnrollCertArgs,
    _config: &CliConfig,
) -> Result<CommandResult<DeviceCertEnrolledOutput>> {
    let ctx = AppContext::new().await?;
    let service = DeviceCertService::new(ctx.db_pool())?;

    let user_id = UserId::new(args.user_id.trim());
    if user_id.as_str().is_empty() {
        return Err(anyhow!("user_id cannot be empty"));
    }

    let record = service
        .enroll(EnrollDeviceCertServiceParams {
            user_id: &user_id,
            fingerprint: &args.fingerprint,
            label: &args.label,
        })
        .await?;

    let output = DeviceCertEnrolledOutput {
        id: record.id.clone(),
        user_id: record.user_id.clone(),
        fingerprint: record.fingerprint.clone(),
        label: record.label.clone(),
        message: format!(
            "Enrolled cert {} for user {}",
            record.fingerprint, record.user_id
        ),
    };

    Ok(CommandResult::text(output).with_title("Device Cert Enrolled"))
}