1
use clap::{
2
  Args,
3
  Subcommand,
4
};
5
use context::Context;
6
use key::KEY_LOCATION_HELP;
7
use mk_lib::schema::TaskRoot;
8

            
9
mod context;
10
mod doctor;
11
mod key;
12
mod utils;
13
mod vault;
14

            
15
/// The struct that represents the secrets command
16
#[derive(Debug, Args)]
17
pub struct Secrets {
18
  #[command(subcommand)]
19
  command: Option<SecretsCommand>,
20

            
21
  #[arg(long, help = "The path to the secret vault")]
22
  vault_location: Option<String>,
23

            
24
  #[arg(long, help = KEY_LOCATION_HELP)]
25
  keys_location: Option<String>,
26

            
27
  #[arg(long, help = "The key name", conflicts_with = "gpg_key_id")]
28
  key_name: Option<String>,
29

            
30
  #[arg(
31
    long,
32
    conflicts_with = "key_name",
33
    help = "GPG key ID or fingerprint for hardware/passphrase-protected keys (delegates crypto to the system gpg binary). Cannot be combined with --key-name."
34
  )]
35
  gpg_key_id: Option<String>,
36
}
37

            
38
/// The available subcommands for the secrets command
39
#[derive(Debug, Subcommand)]
40
enum SecretsCommand {
41
  /// Access private keys using this subcommand
42
  #[command(visible_aliases = ["k"], arg_required_else_help = true, about = "Access private keys")]
43
  Key(key::Key),
44

            
45
  /// Access secret stores using this subcommand
46
  #[command(visible_aliases = ["v"], arg_required_else_help = true, about = "Access secret vault")]
47
  Vault(vault::Vault),
48

            
49
  /// List private keys
50
  #[command(visible_aliases = ["K"], about = "List private keys")]
51
  ListKeys(key::ListKeys),
52

            
53
  /// Initialize a new secret store
54
  #[command(visible_aliases = ["init"], about = "Initialize a new secret vault")]
55
  InitVault(vault::InitVault),
56

            
57
  /// Print resolved secret configuration
58
  #[command(about = "Inspect resolved secret configuration")]
59
  Doctor(doctor::Doctor),
60

            
61
  /// Export a secret
62
  #[command(visible_aliases = ["export", "e"], about = "Export a secret to file")]
63
  ExportSecret(vault::ExportSecret),
64
}
65

            
66
impl Secrets {
67
  pub fn execute(&self, task_root: &TaskRoot) -> anyhow::Result<()> {
68
    let mut context = Context::new(task_root);
69
    if let Some(keys_location) = &self.keys_location {
70
      context.set_keys_location(keys_location);
71
    }
72

            
73
    if let Some(vault_location) = &self.vault_location {
74
      context.set_vault_location(vault_location);
75
    }
76

            
77
    if let Some(key_name) = &self.key_name {
78
      context.set_key_name(key_name);
79
    }
80

            
81
    if let Some(gpg_key_id) = &self.gpg_key_id {
82
      context.set_gpg_key_id(gpg_key_id);
83
    }
84

            
85
    match &self.command {
86
      Some(SecretsCommand::Key(key)) => key.execute(&mut context),
87
      Some(SecretsCommand::Vault(vault)) => vault.execute(&mut context),
88
      Some(SecretsCommand::ListKeys(list_keys)) => list_keys.execute(&context),
89
      Some(SecretsCommand::InitVault(init_store)) => init_store.execute(&context),
90
      Some(SecretsCommand::Doctor(doctor)) => doctor.execute(&context),
91
      Some(SecretsCommand::ExportSecret(export_secret)) => export_secret.execute(&context),
92
      None => Err(anyhow::anyhow!(
93
        "No secrets subcommand given. Run 'mk secrets --help' to see available subcommands."
94
      )),
95
    }
96
  }
97
}