zoom_cli/commands/
config.rs1use crate::config;
2use crate::output::{self, OutputConfig};
3
4pub fn show(profile_arg: Option<&str>, out: &OutputConfig) {
5 let summary = config::load_for_show(profile_arg);
6
7 if out.json {
8 let profiles_json: serde_json::Map<String, serde_json::Value> = summary
9 .profiles
10 .iter()
11 .map(|p| {
12 (
13 p.name.clone(),
14 serde_json::json!({
15 "account_id": masked_or_unset(&p.account_id),
16 "client_id": masked_or_unset(&p.client_id),
17 "client_secret": masked_or_unset(&p.client_secret),
18 }),
19 )
20 })
21 .collect();
22
23 let env_overrides_json: serde_json::Map<String, serde_json::Value> = summary
24 .env_overrides
25 .iter()
26 .map(|(k, v)| {
27 (
28 k.to_string(),
29 serde_json::Value::String(output::mask_credential(v)),
30 )
31 })
32 .collect();
33
34 out.print_data(
35 &serde_json::to_string_pretty(&serde_json::json!({
36 "config_file": summary.config_file.to_string_lossy(),
37 "file_exists": summary.file_exists,
38 "active_profile": summary.active_profile,
39 "profiles": profiles_json,
40 "env_overrides": env_overrides_json,
41 }))
42 .expect("serialize"),
43 );
44 } else {
45 out.print_data(&format!(
46 "Config file: {}{}",
47 summary.config_file.display(),
48 if summary.file_exists {
49 ""
50 } else {
51 " (not found)"
52 },
53 ));
54
55 if summary.profiles.is_empty() && summary.env_overrides.is_empty() {
56 out.print_data("\nNo configuration found. Run `zoom init` to set up credentials.");
57 return;
58 }
59
60 for profile in &summary.profiles {
61 let active_marker = if profile.name == summary.active_profile {
62 " (active)"
63 } else {
64 ""
65 };
66 out.print_data(&format!("\nProfile: {}{}", profile.name, active_marker));
67 out.print_data(&format!(
68 " account_id: {}",
69 masked_or_unset(&profile.account_id)
70 ));
71 out.print_data(&format!(
72 " client_id: {}",
73 masked_or_unset(&profile.client_id)
74 ));
75 out.print_data(&format!(
76 " client_secret: {}",
77 masked_or_unset(&profile.client_secret)
78 ));
79 }
80
81 if !summary.env_overrides.is_empty() {
82 out.print_data("\nEnvironment overrides (take precedence over file):");
83 for (var, val) in &summary.env_overrides {
84 out.print_data(&format!(" {}={}", var, output::mask_credential(val)));
85 }
86 }
87 }
88}
89
90fn masked_or_unset(value: &Option<String>) -> String {
91 match value {
92 Some(v) => output::mask_credential(v),
93 None => "(not set)".to_owned(),
94 }
95}
96
97#[cfg(test)]
98mod tests {
99 use super::*;
100 use crate::test_support::{EnvVarGuard, ProcessEnvLock, set_config_dir_env, write_config};
101 use tempfile::TempDir;
102
103 #[test]
104 fn show_json_includes_active_profile_and_masked_credentials() {
105 let _lock = ProcessEnvLock::acquire().unwrap();
106 let dir = TempDir::new().unwrap();
107 write_config(
108 dir.path(),
109 r#"
110[default]
111account_id = "acct-long-enough-123"
112client_id = "cid-long-enough-456"
113client_secret = "csec-long-enough-789"
114"#,
115 )
116 .unwrap();
117
118 let _cfg_dir = set_config_dir_env(dir.path());
119 let _acct = EnvVarGuard::unset("ZOOM_ACCOUNT_ID");
120 let _cid = EnvVarGuard::unset("ZOOM_CLIENT_ID");
121 let _csec = EnvVarGuard::unset("ZOOM_CLIENT_SECRET");
122 let _prof = EnvVarGuard::unset("ZOOM_PROFILE");
123
124 let summary = config::load_for_show(None);
127 assert_eq!(summary.active_profile, "default");
128 assert!(summary.file_exists);
129 assert_eq!(summary.profiles.len(), 1);
130 assert_eq!(summary.profiles[0].name, "default");
131 assert_eq!(
132 summary.profiles[0].account_id.as_deref(),
133 Some("acct-long-enough-123")
134 );
135 assert!(summary.env_overrides.is_empty());
136 }
137
138 #[test]
139 fn show_lists_all_profiles_with_default_first() {
140 let _lock = ProcessEnvLock::acquire().unwrap();
141 let dir = TempDir::new().unwrap();
142 write_config(
143 dir.path(),
144 r#"
145[default]
146account_id = "def-acct"
147client_id = "def-cid"
148client_secret = "def-csec"
149
150[work]
151account_id = "work-acct"
152client_id = "work-cid"
153client_secret = "work-csec"
154"#,
155 )
156 .unwrap();
157
158 let _cfg_dir = set_config_dir_env(dir.path());
159 let _env_acct = EnvVarGuard::unset("ZOOM_ACCOUNT_ID");
160 let _env_cid = EnvVarGuard::unset("ZOOM_CLIENT_ID");
161 let _env_csec = EnvVarGuard::unset("ZOOM_CLIENT_SECRET");
162 let _env_prof = EnvVarGuard::unset("ZOOM_PROFILE");
163
164 let summary = config::load_for_show(None);
165 assert_eq!(summary.profiles.len(), 2);
166 assert_eq!(summary.profiles[0].name, "default");
167 assert_eq!(summary.profiles[1].name, "work");
168 }
169
170 #[test]
171 fn show_marks_profile_arg_as_active() {
172 let _lock = ProcessEnvLock::acquire().unwrap();
173 let dir = TempDir::new().unwrap();
174 write_config(
175 dir.path(),
176 r#"
177[default]
178account_id = "def-acct"
179client_id = "def-cid"
180client_secret = "def-csec"
181
182[work]
183account_id = "work-acct"
184client_id = "work-cid"
185client_secret = "work-csec"
186"#,
187 )
188 .unwrap();
189
190 let _cfg_dir = set_config_dir_env(dir.path());
191 let _env_acct = EnvVarGuard::unset("ZOOM_ACCOUNT_ID");
192 let _env_cid = EnvVarGuard::unset("ZOOM_CLIENT_ID");
193 let _env_csec = EnvVarGuard::unset("ZOOM_CLIENT_SECRET");
194 let _env_prof = EnvVarGuard::unset("ZOOM_PROFILE");
195
196 let summary = config::load_for_show(Some("work"));
197 assert_eq!(summary.active_profile, "work");
198 }
199
200 #[test]
201 fn show_reports_env_overrides() {
202 let _lock = ProcessEnvLock::acquire().unwrap();
203 let dir = TempDir::new().unwrap();
204 let _cfg_dir = set_config_dir_env(dir.path());
205 let _acct = EnvVarGuard::set("ZOOM_ACCOUNT_ID", "env-account-id-long");
206 let _cid = EnvVarGuard::unset("ZOOM_CLIENT_ID");
207 let _csec = EnvVarGuard::unset("ZOOM_CLIENT_SECRET");
208 let _prof = EnvVarGuard::unset("ZOOM_PROFILE");
209
210 let summary = config::load_for_show(None);
211 assert_eq!(summary.env_overrides.len(), 1);
212 assert_eq!(summary.env_overrides[0].0, "ZOOM_ACCOUNT_ID");
213 assert_eq!(summary.env_overrides[0].1, "env-account-id-long");
214 }
215
216 #[test]
217 fn show_handles_missing_config_file() {
218 let _lock = ProcessEnvLock::acquire().unwrap();
219 let dir = TempDir::new().unwrap();
220 let _cfg_dir = set_config_dir_env(dir.path());
221 let _acct = EnvVarGuard::unset("ZOOM_ACCOUNT_ID");
222 let _cid = EnvVarGuard::unset("ZOOM_CLIENT_ID");
223 let _csec = EnvVarGuard::unset("ZOOM_CLIENT_SECRET");
224 let _prof = EnvVarGuard::unset("ZOOM_PROFILE");
225
226 let summary = config::load_for_show(None);
227 assert!(!summary.file_exists);
228 assert!(summary.profiles.is_empty());
229 }
230
231 #[test]
232 fn masked_or_unset_masks_present_values() {
233 assert_eq!(
234 masked_or_unset(&Some("abcdefghijklmnop".to_owned())),
235 "abcdef…mnop"
236 );
237 assert_eq!(masked_or_unset(&None), "(not set)");
238 }
239}