wasmer_cli/commands/app/secrets/
reveal.rs

1use super::utils;
2use crate::{
3    commands::{AsyncCliCommand, app::util::AppIdentFlag},
4    config::WasmerEnv,
5    opts::ListFormatOpts,
6    utils::render::{ItemFormat, ListFormat},
7};
8use dialoguer::theme::ColorfulTheme;
9use is_terminal::IsTerminal;
10use std::path::PathBuf;
11
12/// Reveal the value of an existing app secret.
13#[derive(clap::Parser, Debug)]
14pub struct CmdAppSecretsReveal {
15    /* --- Common flags --- */
16    #[clap(flatten)]
17    pub env: WasmerEnv,
18
19    /// Don't print any message.
20    #[clap(long)]
21    pub quiet: bool,
22
23    /// Do not prompt for user input.
24    #[clap(long, default_value_t = !std::io::stdin().is_terminal())]
25    pub non_interactive: bool,
26
27    #[clap(flatten)]
28    pub fmt: Option<ListFormatOpts>,
29
30    /* --- Flags --- */
31    #[clap(flatten)]
32    pub app_id: AppIdentFlag,
33
34    /// The path to the directory where the config file for the application will be written to.
35    #[clap(long = "app-dir", conflicts_with = "app")]
36    pub app_dir_path: Option<PathBuf>,
37
38    /// Reveal all the secrets related to an app.
39    #[clap(long, conflicts_with = "name")]
40    pub all: bool,
41
42    /* --- Parameters --- */
43    /// The name of the secret to get the value of.
44    #[clap(name = "name")]
45    pub secret_name: Option<String>,
46}
47
48impl CmdAppSecretsReveal {
49    fn get_secret_name(&self) -> anyhow::Result<String> {
50        if let Some(name) = &self.secret_name {
51            return Ok(name.clone());
52        }
53
54        if self.non_interactive {
55            anyhow::bail!("No secret name given. Provide one as a positional argument.")
56        } else {
57            let theme = ColorfulTheme::default();
58            Ok(dialoguer::Input::with_theme(&theme)
59                .with_prompt("Enter the name of the secret:")
60                .interact_text()?)
61        }
62    }
63}
64
65#[async_trait::async_trait]
66impl AsyncCliCommand for CmdAppSecretsReveal {
67    type Output = ();
68
69    async fn run_async(self) -> Result<Self::Output, anyhow::Error> {
70        let client = self.env.client()?;
71        let app_id = super::utils::get_app_id(
72            &client,
73            self.app_id.app.as_ref(),
74            self.app_dir_path.as_ref(),
75            self.quiet,
76            self.non_interactive,
77        )
78        .await?;
79
80        if !self.all {
81            let name = self.get_secret_name()?;
82
83            let value = utils::get_secret_value_by_name(&client, &app_id, &name).await?;
84
85            let secret = utils::Secret { name, value };
86
87            if let Some(fmt) = &self.fmt {
88                let fmt = match fmt.format {
89                    ListFormat::Json => ItemFormat::Json,
90                    ListFormat::Yaml => ItemFormat::Yaml,
91                    ListFormat::Table => ItemFormat::Table,
92                    ListFormat::ItemTable => {
93                        anyhow::bail!("The 'item-table' format is not available for single values.")
94                    }
95                };
96                println!("{}", fmt.render(&secret));
97            } else {
98                print!("{}", secret.value);
99            }
100        } else {
101            let secrets: Vec<utils::Secret> = utils::reveal_secrets(&client, &app_id).await?;
102
103            if let Some(fmt) = &self.fmt {
104                println!("{}", fmt.format.render(secrets.as_slice()));
105            } else {
106                for secret in secrets {
107                    println!(
108                        "{}=\"{}\"",
109                        secret.name,
110                        utils::render::sanitize_value(&secret.value)
111                    );
112                }
113            }
114        }
115
116        Ok(())
117    }
118}