1use std::collections::HashMap;
2
3use anyhow::bail;
4use clap::Subcommand;
5use tracing::trace;
6use wash_lib::cli::{input_vec_to_hashmap, CliConnectionOpts, CommandOutput, OutputKind};
7use wasmcloud_secrets_types::{SecretConfig, SECRET_PREFIX};
8
9use crate::cmd;
10
11#[derive(Debug, Clone, Subcommand)]
12pub enum SecretsCliCommand {
13 #[clap(name = "put", alias = "create", about = "Put secret reference")]
14 PutCommand {
15 #[clap(flatten)]
16 opts: CliConnectionOpts,
17 #[clap(name = "name")]
19 name: String,
20 #[clap(name = "backend")]
22 backend: String,
23 #[clap(name = "key")]
25 key: String,
26 #[clap(long = "field")]
28 field: Option<String>,
29 #[clap(short = 'v', long = "version")]
31 version: Option<String>,
32 #[clap(long = "property")]
34 policy_properties: Vec<String>,
35 },
36
37 #[clap(name = "get")]
39 GetCommand {
40 #[clap(flatten)]
41 opts: CliConnectionOpts,
42 #[clap(name = "name")]
43 name: String,
44 },
45
46 #[clap(name = "del", alias = "delete")]
48 DelCommand {
49 #[clap(flatten)]
50 opts: CliConnectionOpts,
51 #[clap(name = "name")]
52 name: String,
53 },
54}
55
56pub async fn handle_command(
57 command: SecretsCliCommand,
58 output_kind: OutputKind,
59) -> anyhow::Result<CommandOutput> {
60 match command {
61 SecretsCliCommand::PutCommand {
62 opts,
63 name,
64 backend,
65 key,
66 field,
67 version,
68 policy_properties,
69 } => {
70 let policy_property_map = input_vec_to_hashmap(policy_properties)?;
71 let secret_name = name.clone();
72 let secret_config = SecretConfig::new(
73 secret_name,
74 backend,
75 key,
76 field,
77 version,
78 policy_property_map
79 .into_iter()
80 .map(|(k, v)| (k, v.into()))
81 .collect(),
82 );
83 trace!(?secret_config, "Putting secret config");
84 let values: HashMap<String, String> = secret_config.try_into()?;
85
86 cmd::config::put::invoke(opts, &secret_configdata_key(&name), values, output_kind).await
87 }
88 SecretsCliCommand::GetCommand { opts, name } => {
89 cmd::config::get::invoke(opts, &secret_configdata_key(&name), output_kind).await
90 }
91 SecretsCliCommand::DelCommand { opts, name } => {
92 cmd::config::delete::invoke(opts, &secret_configdata_key(&name), output_kind).await
93 }
94 }
95}
96
97pub(crate) fn ensure_not_secret(name: &str) -> anyhow::Result<()> {
99 if name.starts_with(SECRET_PREFIX) {
100 bail!("Configuration names cannot start with '{SECRET_PREFIX}'. Did you mean to use the 'secrets' command?");
101 }
102 Ok(())
103}
104
105pub(crate) fn is_secret(name: &str) -> bool {
107 name.starts_with(SECRET_PREFIX)
108}
109
110pub(crate) fn secret_configdata_key(name: &str) -> String {
112 if is_secret(name) {
113 name.to_string()
114 } else {
115 format!("{SECRET_PREFIX}_{}", name)
116 }
117}