use std::error::Error;
use clap::{Args, Subcommand};
use covert_sdk::{
kv::{
CreateSecretParams, HardDeleteSecretParams, RecoverSecretParams, SetConfigParams,
SoftDeleteSecretParams,
},
Client,
};
use crate::handle_resp;
#[derive(Args, Debug)]
pub struct Kv {
#[clap(subcommand)]
subcommand: KvSubcommand,
}
fn parse_key_val<T, U>(s: &str) -> Result<(T, U), Box<dyn Error + Send + Sync + 'static>>
where
T: std::str::FromStr,
T::Err: Error + Send + Sync + 'static,
U: std::str::FromStr,
U::Err: Error + Send + Sync + 'static,
{
let pos = s
.find('=')
.ok_or_else(|| format!("invalid key=value: no `=` found in `{s}`"))?;
Ok((s[..pos].parse()?, s[pos + 1..].parse()?))
}
#[derive(Subcommand, Debug)]
pub enum KvSubcommand {
#[command(about = "add new secret")]
Put {
#[arg(help = "key to add secret to")]
key: String,
#[arg(short, long, value_parser = parse_key_val::<String, String>)]
data: Vec<(String, String)>,
#[arg(short, long)]
path: String,
},
#[command(about = "retrieve secret")]
Get {
#[arg(help = "key to retrieve")]
key: String,
#[arg(short, long)]
path: String,
#[arg(short, long)]
version: Option<u32>,
},
#[command(about = "soft-delete secret, can be recovered with the \"recover\" subcommand")]
Delete {
#[arg(help = "key to delete")]
key: String,
#[arg(short, long, use_value_delimiter = true, value_delimiter = ',')]
versions: Vec<u32>,
#[arg(short, long)]
path: String,
},
#[command(about = "hard-delete secret, cannot be recovered")]
HardDelete {
#[arg(help = "key to delete")]
key: String,
#[arg(short, long, use_value_delimiter = true, value_delimiter = ',')]
versions: Vec<u32>,
#[arg(short, long)]
path: String,
},
#[command(about = "recover soft-deleted secret")]
Recover {
#[arg(help = "key to recover")]
key: String,
#[arg(short, long, use_value_delimiter = true, value_delimiter = ',')]
versions: Vec<u32>,
#[arg(short, long)]
path: String,
},
#[command(about = "update config for the kv backend")]
SetConfig {
#[arg(help = "path where the KV backend is mounted")]
path: String,
#[arg(long)]
max_versions: u32,
},
#[command(about = "read config for the kv backend")]
Config {
#[arg(help = "path where the KV backend is mounted")]
path: String,
},
}
impl Kv {
pub async fn handle(self, sdk: &Client) {
match self.subcommand {
KvSubcommand::Put { key, data, path } => {
let resp = sdk
.kv
.create(
&path,
&key,
&CreateSecretParams {
data: data.into_iter().collect(),
},
)
.await;
handle_resp(resp);
}
KvSubcommand::Get { key, path, version } => {
let resp = sdk.kv.read(&path, &key, version).await;
handle_resp(resp);
}
KvSubcommand::Recover {
key,
path,
versions,
} => {
let resp = sdk
.kv
.recover(&path, &key, &RecoverSecretParams { versions })
.await;
handle_resp(resp);
}
KvSubcommand::SetConfig { max_versions, path } => {
let resp = sdk
.kv
.set_config(&path, &SetConfigParams { max_versions })
.await;
handle_resp(resp);
}
KvSubcommand::Config { path } => {
let resp = sdk.kv.read_config(&path).await;
handle_resp(resp);
}
KvSubcommand::Delete {
key,
versions,
path,
} => {
let resp = sdk
.kv
.delete(&path, &key, &SoftDeleteSecretParams { versions })
.await;
handle_resp(resp);
}
KvSubcommand::HardDelete {
key,
versions,
path,
} => {
let resp = sdk
.kv
.hard_delete(&path, &key, &HardDeleteSecretParams { versions })
.await;
handle_resp(resp);
}
}
}
}