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 run;
pub mod secrets;
pub mod setup;
pub mod shell;
pub mod sync;
pub mod team;
pub mod whoami;
pub mod check;
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, long, global = true)]
pub verbose: bool,
#[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),
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,
}
pub fn execute(command: Command) -> 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),
Add { key } => add::execute(&key),
Set { key, value, force } => secrets::set(&key, &value, force),
Get { key } => secrets::get(&key),
Rm { key } => secrets::rm(&key),
List { json } => secrets::list(json),
Knock { name } => knock::execute(name),
Pending => pending::execute(),
Admit { name } => admit::execute(&name),
Sync { dry_run, force } => sync::execute(dry_run, force),
Dot => dot::execute(),
Run { command } => run::execute(&command),
Env => shell::execute(),
Team(action) => match action {
TeamAction::Add { name, key } => team::add(&name, &key),
TeamAction::List { json } => team::list(json),
TeamAction::Rm { name } => team::rm(&name),
},
Secrets(cmd) => match cmd {
SecretsCommand::Lock => secrets::lock(),
SecretsCommand::Unlock => secrets::unlock(),
SecretsCommand::Import { path } => secrets::import(&path),
SecretsCommand::Export => secrets::export(),
SecretsCommand::Diff => secrets::diff(),
SecretsCommand::Rotate => secrets::rotate(),
},
Check(cmd) => match cmd {
CheckCommand::Status => check::status(),
CheckCommand::Audit => check::audit(),
},
Completions { shell } => completions::execute(shell),
}
}