pub mod add;
pub mod admit;
pub mod banner;
pub mod completions;
pub mod dot;
pub mod init;
pub mod knock;
pub mod output;
pub mod pending;
pub mod resolve;
pub mod run;
pub mod secrets;
pub mod setup;
pub mod shell;
pub mod sync;
pub mod team;
pub mod whoami;
pub mod check;
pub mod vault;
use clap::builder::styling::{AnsiColor, Effects, Styles};
use clap::{Parser, Subcommand};
const STYLES: Styles = Styles::styled()
.header(AnsiColor::Green.on_default().effects(Effects::BOLD))
.usage(AnsiColor::Green.on_default().effects(Effects::BOLD))
.literal(AnsiColor::Cyan.on_default().effects(Effects::BOLD))
.placeholder(AnsiColor::Cyan.on_default())
.valid(AnsiColor::Green.on_default().effects(Effects::BOLD))
.invalid(AnsiColor::Red.on_default().effects(Effects::BOLD))
.error(AnsiColor::Red.on_default().effects(Effects::BOLD));
#[derive(Parser)]
#[command(
name = "dugout",
about = "Git-native secrets manager for development teams",
version,
styles = STYLES
)]
pub struct Cli {
#[arg(short = 'v', long, global = true)]
pub verbose: bool,
#[arg(long = "vault", global = true, env = "DUGOUT_VAULT")]
pub vault: Option<String>,
#[command(subcommand)]
pub command: Command,
}
#[derive(Subcommand)]
pub enum Command {
Setup {
#[arg(short, long)]
force: bool,
#[arg(short, long)]
name: Option<String>,
#[arg(short, long, value_name = "PATH")]
output: Option<String>,
},
Whoami,
Init {
#[arg(short, long)]
name: Option<String>,
#[arg(long)]
no_banner: bool,
#[arg(long, value_name = "KEY")]
kms: Option<String>,
},
Add {
key: String,
},
Set {
key: String,
value: String,
#[arg(short, long)]
force: bool,
},
Get {
key: String,
},
Rm {
key: String,
},
List {
#[arg(long)]
json: bool,
},
Knock {
name: Option<String>,
},
Pending,
Admit {
name: String,
},
Sync {
#[arg(long)]
dry_run: bool,
#[arg(long)]
force: bool,
},
#[command(name = ".")]
Dot,
Run {
#[arg(trailing_var_arg = true)]
command: Vec<String>,
},
Env,
#[command(subcommand)]
Team(TeamAction),
#[command(subcommand)]
Secrets(SecretsCommand),
#[command(subcommand)]
Check(CheckCommand),
#[command(subcommand)]
Vault(VaultCommand),
Completions {
#[arg(value_enum)]
shell: Shell,
},
}
#[derive(clap::ValueEnum, Clone, Debug)]
pub enum Shell {
Bash,
Zsh,
Fish,
PowerShell,
}
#[derive(Subcommand)]
pub enum TeamAction {
Add {
name: String,
key: String,
},
List {
#[arg(long)]
json: bool,
},
Rm {
name: String,
},
}
#[derive(Subcommand)]
pub enum SecretsCommand {
Lock,
Unlock,
Import {
path: String,
},
Export,
Diff,
Rotate,
}
#[derive(Subcommand)]
pub enum CheckCommand {
Status,
Audit,
}
#[derive(Subcommand)]
pub enum VaultCommand {
List {
#[arg(long)]
json: bool,
},
}
pub fn execute(command: Command, vault: Option<String>) -> crate::error::Result<()> {
use Command::*;
match command {
Setup {
force,
name,
output,
} => setup::execute(force, name, output),
Whoami => whoami::execute(),
Init {
name,
no_banner,
kms,
} => init::execute(name, no_banner, kms, vault),
Add { key } => add::execute(&key, vault),
Set { key, value, force } => secrets::set(&key, &value, force, vault),
Get { key } => secrets::get(&key, vault),
Rm { key } => secrets::rm(&key, vault),
List { json } => secrets::list(json, vault),
Knock { name } => knock::execute(name, vault),
Pending => pending::execute(vault),
Admit { name } => admit::execute(&name, vault),
Sync { dry_run, force } => sync::execute(dry_run, force, vault),
Dot => dot::execute(vault),
Run { command: cmd } => run::execute(&cmd, vault),
Env => shell::execute(vault),
Team(action) => match action {
TeamAction::Add { name, key } => team::add(&name, &key, vault),
TeamAction::List { json } => team::list(json, vault),
TeamAction::Rm { name } => team::rm(&name, vault),
},
Secrets(cmd) => match cmd {
SecretsCommand::Lock => secrets::lock(vault),
SecretsCommand::Unlock => secrets::unlock(vault),
SecretsCommand::Import { path } => secrets::import(&path, vault),
SecretsCommand::Export => secrets::export(vault),
SecretsCommand::Diff => secrets::diff(vault),
SecretsCommand::Rotate => secrets::rotate(vault),
},
Check(cmd) => match cmd {
CheckCommand::Status => check::status(vault),
CheckCommand::Audit => check::audit(),
},
Vault(cmd) => match cmd {
VaultCommand::List { json } => vault::list::execute(json),
},
Completions { shell } => completions::execute(shell),
}
}