#![cfg_attr(test, allow(clippy::indexing_slicing))]
pub mod client_cli;
use basil_core::{agent_cli, bundle_cli, init};
use clap::{CommandFactory, Parser, Subcommand};
#[derive(Debug, Parser)]
#[command(name = "basil", version, about = "Basil broker and operator tool")]
pub struct Cli {
#[arg(long, env = "BASIL_SOCKET", global = true)]
pub socket: Option<String>,
#[command(subcommand)]
pub command: Command,
}
#[derive(Debug, Subcommand)]
pub enum Command {
Init(Box<init::InitArgs>),
Agent(agent_cli::RunArgs),
#[command(subcommand)]
Bundle(Box<bundle_cli::BundleCommand>),
Explain(agent_cli::ExplainArgs),
Doctor(agent_cli::DoctorArgs),
#[command(flatten)]
Client(client_cli::Command),
}
#[must_use]
pub fn cli() -> clap::Command {
Cli::command()
}
#[cfg(test)]
mod tests {
use super::*;
fn parse(args: &[&str]) -> Cli {
Cli::try_parse_from(args).expect("parse cli")
}
#[test]
fn bundle_is_top_level_command() {
let cli = parse(&[
"basil",
"bundle",
"verify",
"creds.sealed",
"--open",
"passphrase:file=/run/pass",
]);
assert!(matches!(cli.command, Command::Bundle(_)));
}
#[test]
fn old_config_bundle_path_is_not_user_facing() {
let err = Cli::try_parse_from(["basil", "config", "bundle", "verify"])
.expect_err("config bundle must not remain as a compatibility command");
assert!(
err.to_string().contains("unrecognized subcommand")
|| err.to_string().contains("invalid subcommand"),
"{err}"
);
}
#[test]
fn set_backend_accepts_structured_backend_value() {
let cli = parse(&[
"basil",
"bundle",
"set-backend",
"creds.sealed",
"--backend",
"id=aws1,type=aws-kms,region=us-east-1,profile=prod",
"--open",
"passphrase:file=/run/pass",
]);
assert!(matches!(cli.command, Command::Bundle(_)));
}
}