1#![cfg_attr(test, allow(clippy::indexing_slicing))]
9
10pub mod client_cli;
11
12use basil_core::{agent_cli, bundle_cli, init};
13use clap::{CommandFactory, Parser, Subcommand};
14
15#[derive(Debug, Parser)]
17#[command(name = "basil", version, about = "Basil broker and operator tool")]
18pub struct Cli {
19 #[arg(long, env = "BASIL_SOCKET", global = true)]
21 pub socket: Option<String>,
22
23 #[command(subcommand)]
24 pub command: Command,
25}
26
27#[derive(Debug, Subcommand)]
29pub enum Command {
30 Agent(agent_cli::RunArgs),
32 #[command(subcommand)]
34 Bundle(Box<bundle_cli::BundleCommand>),
35 #[command(subcommand)]
37 Config(Box<ConfigCommand>),
38 Doctor(agent_cli::DoctorArgs),
40 #[command(flatten)]
41 Client(client_cli::Command),
42}
43
44#[derive(Debug, Subcommand)]
46pub enum ConfigCommand {
47 Init(init::InitArgs),
49 Check(agent_cli::CheckArgs),
51 Explain(agent_cli::ExplainArgs),
53}
54
55#[must_use]
58pub fn cli() -> clap::Command {
59 Cli::command()
60}
61
62#[cfg(test)]
63mod tests {
64 use super::*;
65
66 fn parse(args: &[&str]) -> Cli {
67 Cli::try_parse_from(args).expect("parse cli")
68 }
69
70 #[test]
71 fn bundle_is_top_level_command() {
72 let cli = parse(&[
73 "basil",
74 "bundle",
75 "verify",
76 "creds.sealed",
77 "--open",
78 "passphrase:file=/run/pass",
79 ]);
80 assert!(matches!(cli.command, Command::Bundle(_)));
81 }
82
83 #[test]
84 fn old_config_bundle_path_is_not_user_facing() {
85 let err = Cli::try_parse_from(["basil", "config", "bundle", "verify"])
86 .expect_err("config bundle must not remain as a compatibility command");
87 assert!(
88 err.to_string().contains("unrecognized subcommand")
89 || err.to_string().contains("invalid subcommand"),
90 "{err}"
91 );
92 }
93
94 #[test]
95 fn set_backend_accepts_structured_backend_value() {
96 let cli = parse(&[
97 "basil",
98 "bundle",
99 "set-backend",
100 "creds.sealed",
101 "--backend",
102 "id=aws1,type=aws-kms,region=us-east-1,profile=prod",
103 "--open",
104 "passphrase:file=/run/pass",
105 ]);
106 assert!(matches!(cli.command, Command::Bundle(_)));
107 }
108}