wasmer_cli/commands/app/secrets/utils/
mod.rs1pub(crate) mod render;
2use anyhow::Context;
3use colored::Colorize;
4use std::{
5 env::current_dir,
6 path::{Path, PathBuf},
7 str::FromStr,
8};
9use wasmer_backend_api::{WasmerClient, types::Secret as BackendSecret};
10
11use crate::commands::app::util::{AppIdent, get_app_config_from_dir, prompt_app_ident};
12
13#[derive(serde::Serialize, serde::Deserialize)]
14pub(super) struct Secret {
15 pub name: String,
16 pub value: String,
17}
18
19pub(super) async fn read_secrets_from_file(path: &Path) -> anyhow::Result<Vec<Secret>> {
20 let mut ret = vec![];
21 for item in dotenvy::from_path_iter(path)? {
22 let (name, value) = item?;
23 ret.push(Secret { name, value })
24 }
25 Ok(ret)
26}
27
28pub(super) async fn get_secret_by_name(
29 client: &WasmerClient,
30 app_id: &str,
31 secret_name: &str,
32) -> anyhow::Result<Option<BackendSecret>> {
33 wasmer_backend_api::query::get_app_secret_by_name(client, app_id, secret_name).await
34}
35pub(crate) async fn get_secrets(
36 client: &WasmerClient,
37 app_id: &str,
38) -> anyhow::Result<Vec<wasmer_backend_api::types::Secret>> {
39 wasmer_backend_api::query::get_all_app_secrets(client, app_id).await
40}
41
42pub(crate) async fn get_secret_value(
43 client: &WasmerClient,
44 secret: &wasmer_backend_api::types::Secret,
45) -> anyhow::Result<String> {
46 wasmer_backend_api::query::get_app_secret_value_by_id(client, secret.id.clone().into_inner())
47 .await?
48 .ok_or_else(|| {
49 anyhow::anyhow!(
50 "No value found for secret with name '{}'",
51 secret.name.bold()
52 )
53 })
54}
55
56pub(crate) async fn get_secret_value_by_name(
57 client: &WasmerClient,
58 app_id: &str,
59 secret_name: &str,
60) -> anyhow::Result<String> {
61 match get_secret_by_name(client, app_id, secret_name).await? {
62 Some(secret) => get_secret_value(client, &secret).await,
63 None => anyhow::bail!("No secret found with name {secret_name} for app {app_id}"),
64 }
65}
66
67pub(crate) async fn reveal_secrets(
68 client: &WasmerClient,
69 app_id: &str,
70) -> anyhow::Result<Vec<Secret>> {
71 let secrets = wasmer_backend_api::query::get_all_app_secrets(client, app_id).await?;
72 let mut ret = vec![];
73 for secret in secrets {
74 let name = secret.name.clone();
75 let value = get_secret_value(client, &secret).await?;
76 ret.push(Secret { name, value });
77 }
78
79 Ok(ret)
80}
81
82#[derive(Debug, serde::Serialize)]
84pub(super) struct BackendSecretWrapper(pub BackendSecret);
85
86impl From<BackendSecret> for BackendSecretWrapper {
87 fn from(value: BackendSecret) -> Self {
88 Self(value)
89 }
90}
91
92pub(super) async fn get_app_id(
94 client: &WasmerClient,
95 app: Option<&AppIdent>,
96 app_dir_path: Option<&PathBuf>,
97 quiet: bool,
98 non_interactive: bool,
99) -> anyhow::Result<String> {
100 if let Some(app_id) = app {
101 let app = app_id.resolve(client).await?;
102 return Ok(app.id.into_inner());
103 }
104
105 let path = if let Some(path) = app_dir_path {
106 path.clone()
107 } else {
108 current_dir()?
109 };
110
111 if let Ok(r) = get_app_config_from_dir(&path) {
112 let (app, _) = r;
113
114 let app_name = if let Some(owner) = &app.owner {
115 format!(
116 "{owner}/{}",
117 &app.name.clone().context("App name has to be specified")?
118 )
119 } else {
120 app.name
121 .clone()
122 .context("App name has to be specified")?
123 .to_string()
124 };
125
126 let id = if let Some(id) = &app.app_id {
127 Some(id.clone())
128 } else if let Ok(app_ident) = AppIdent::from_str(&app_name) {
129 if let Ok(app) = app_ident.resolve(client).await {
130 Some(app.id.into_inner())
131 } else {
132 if !quiet {
133 eprintln!(
134 "{}: the app found in {} does not exist.\n{}: maybe it was not deployed yet?",
135 "Warning".bold().yellow(),
136 format!("'{}'", path.display()).dimmed(),
137 "Hint".bold()
138 );
139 }
140 None
141 }
142 } else {
143 None
144 };
145
146 if let Some(id) = id {
147 if !quiet {
148 if let Some(owner) = &app.owner {
149 eprintln!(
150 "Managing secrets related to app {} ({owner}).",
151 app.name.context("App name has to be specified")?.bold()
152 );
153 } else {
154 eprintln!(
155 "Managing secrets related to app {}.",
156 app.name.context("App name has to be specified")?.bold()
157 );
158 }
159 }
160 return Ok(id);
161 }
162 } else if let Some(path) = app_dir_path {
163 anyhow::bail!(
164 "No app configuration file found in path {}.",
165 path.display()
166 )
167 }
168
169 if non_interactive {
170 anyhow::bail!("No app id given. Provide one using the `--app` flag.")
171 } else {
172 let id = prompt_app_ident("Enter the name of the app")?;
173 let app = id.resolve(client).await?;
174 Ok(app.id.into_inner())
175 }
176}