Skip to main content

cdk_mintd/env_vars/
management_rpc.rs

1//! Management RPC environment variables
2
3use std::env;
4
5use crate::config::MintManagementRpc;
6
7// Mint RPC Server environment variables
8pub const ENV_MINT_MANAGEMENT_ENABLED: &str = "CDK_MINTD_MANAGEMENT_ENABLED";
9pub const ENV_MINT_MANAGEMENT_ENABLED_LEGACY: &str = "CDK_MINTD_MINT_MANAGEMENT_ENABLED";
10pub const ENV_MINT_MANAGEMENT_ADDRESS: &str = "CDK_MINTD_MANAGEMENT_ADDRESS";
11pub const ENV_MINT_MANAGEMENT_PORT: &str = "CDK_MINTD_MANAGEMENT_PORT";
12pub const ENV_MINT_MANAGEMENT_TLS_DIR: &str = "CDK_MINTD_MANAGEMENT_TLS_DIR";
13pub const ENV_MINT_MANAGEMENT_ALLOW_INSECURE: &str = "CDK_MINTD_MANAGEMENT_ALLOW_INSECURE";
14pub const ENV_MINT_MANAGEMENT_ALLOW_MINT_QUOTE_PAYMENT_OVERRIDE: &str =
15    "CDK_MINTD_MANAGEMENT_ALLOW_MINT_QUOTE_PAYMENT_OVERRIDE";
16
17impl MintManagementRpc {
18    pub fn from_env(mut self) -> Self {
19        if let Some(enabled) = super::bool_override(ENV_MINT_MANAGEMENT_ENABLED)
20            .or_else(|| super::bool_override(ENV_MINT_MANAGEMENT_ENABLED_LEGACY))
21        {
22            self.enabled = enabled;
23        }
24
25        if let Ok(address) = env::var(ENV_MINT_MANAGEMENT_ADDRESS) {
26            self.address = Some(address);
27        }
28
29        if let Ok(port) = env::var(ENV_MINT_MANAGEMENT_PORT) {
30            if let Ok(port) = port.parse::<u16>() {
31                self.port = Some(port);
32            }
33        }
34
35        if let Ok(tls_dir) = env::var(ENV_MINT_MANAGEMENT_TLS_DIR) {
36            self.tls_dir = Some(tls_dir.into());
37        }
38
39        if let Some(allow_insecure) = super::bool_override(ENV_MINT_MANAGEMENT_ALLOW_INSECURE) {
40            self.allow_insecure = allow_insecure;
41        }
42
43        if let Ok(allow_override) = env::var(ENV_MINT_MANAGEMENT_ALLOW_MINT_QUOTE_PAYMENT_OVERRIDE)
44        {
45            self.allow_mint_quote_payment_override = allow_override.parse().unwrap_or(false);
46        }
47
48        self
49    }
50}
51
52#[cfg(test)]
53mod tests {
54    use std::collections::BTreeSet;
55    use std::path::PathBuf;
56
57    use super::*;
58
59    fn env_lock() -> std::sync::MutexGuard<'static, ()> {
60        crate::test_utils::env_lock()
61    }
62
63    fn clear_env_vars() {
64        env::remove_var(ENV_MINT_MANAGEMENT_ENABLED);
65        env::remove_var(ENV_MINT_MANAGEMENT_ENABLED_LEGACY);
66        env::remove_var(ENV_MINT_MANAGEMENT_ADDRESS);
67        env::remove_var(ENV_MINT_MANAGEMENT_PORT);
68        env::remove_var(ENV_MINT_MANAGEMENT_TLS_DIR);
69        env::remove_var(ENV_MINT_MANAGEMENT_ALLOW_INSECURE);
70        env::remove_var(ENV_MINT_MANAGEMENT_ALLOW_MINT_QUOTE_PAYMENT_OVERRIDE);
71    }
72
73    #[test]
74    fn management_env_var_names_share_consistent_prefix() {
75        let names = [
76            ENV_MINT_MANAGEMENT_ENABLED,
77            ENV_MINT_MANAGEMENT_ADDRESS,
78            ENV_MINT_MANAGEMENT_PORT,
79            ENV_MINT_MANAGEMENT_TLS_DIR,
80            ENV_MINT_MANAGEMENT_ALLOW_INSECURE,
81            ENV_MINT_MANAGEMENT_ALLOW_MINT_QUOTE_PAYMENT_OVERRIDE,
82        ];
83
84        let prefixes: BTreeSet<&str> = names
85            .iter()
86            .map(|name| {
87                let idx = name
88                    .find("MANAGEMENT")
89                    .expect("management env var name should contain MANAGEMENT");
90                &name[..idx]
91            })
92            .collect();
93
94        assert_eq!(
95            prefixes.len(),
96            1,
97            "inconsistent management RPC env var prefixes: {prefixes:?}"
98        );
99    }
100
101    #[test]
102    fn management_rpc_from_env_reads_canonical_env_vars() {
103        let _guard = env_lock();
104        clear_env_vars();
105
106        env::set_var(ENV_MINT_MANAGEMENT_ENABLED, "true");
107        env::set_var(ENV_MINT_MANAGEMENT_ADDRESS, "0.0.0.0");
108        env::set_var(ENV_MINT_MANAGEMENT_PORT, "10000");
109        env::set_var(ENV_MINT_MANAGEMENT_TLS_DIR, "/var/lib/cdk/tls");
110        env::set_var(ENV_MINT_MANAGEMENT_ALLOW_INSECURE, "true");
111        env::set_var(
112            ENV_MINT_MANAGEMENT_ALLOW_MINT_QUOTE_PAYMENT_OVERRIDE,
113            "true",
114        );
115
116        let management_rpc = MintManagementRpc::default().from_env();
117
118        assert!(management_rpc.enabled);
119        assert_eq!(management_rpc.address.as_deref(), Some("0.0.0.0"));
120        assert_eq!(management_rpc.port, Some(10000));
121        assert_eq!(
122            management_rpc.tls_dir,
123            Some(PathBuf::from("/var/lib/cdk/tls"))
124        );
125        assert!(management_rpc.allow_insecure);
126        assert!(management_rpc.allow_mint_quote_payment_override);
127
128        clear_env_vars();
129    }
130
131    #[test]
132    fn management_rpc_from_env_still_reads_legacy_enabled_env_var() {
133        let _guard = env_lock();
134        clear_env_vars();
135
136        env::set_var(ENV_MINT_MANAGEMENT_ENABLED_LEGACY, "true");
137
138        let management_rpc = MintManagementRpc::default().from_env();
139
140        assert!(management_rpc.enabled);
141
142        clear_env_vars();
143    }
144
145    #[test]
146    fn management_rpc_from_env_allows_no_tls_configuration() {
147        let _guard = env_lock();
148        clear_env_vars();
149
150        env::set_var(ENV_MINT_MANAGEMENT_ENABLED, "true");
151
152        let management_rpc = MintManagementRpc::default().from_env();
153
154        assert!(management_rpc.enabled);
155        assert_eq!(management_rpc.tls_dir, None);
156        assert!(!management_rpc.allow_insecure);
157        assert!(!management_rpc.allow_mint_quote_payment_override);
158
159        clear_env_vars();
160    }
161
162    #[test]
163    fn management_rpc_security_overrides_fail_closed() {
164        let _guard = env_lock();
165        clear_env_vars();
166        for name in [
167            ENV_MINT_MANAGEMENT_ENABLED,
168            ENV_MINT_MANAGEMENT_ENABLED_LEGACY,
169            ENV_MINT_MANAGEMENT_ALLOW_INSECURE,
170        ] {
171            for value in ["false", "not-a-boolean"] {
172                env::set_var(name, value);
173                let config = MintManagementRpc {
174                    enabled: true,
175                    allow_insecure: true,
176                    ..Default::default()
177                }
178                .from_env();
179                let actual = if name == ENV_MINT_MANAGEMENT_ALLOW_INSECURE {
180                    config.allow_insecure
181                } else {
182                    config.enabled
183                };
184                assert!(!actual, "{name}={value}");
185            }
186            env::remove_var(name);
187        }
188        let configured = MintManagementRpc {
189            enabled: true,
190            allow_insecure: true,
191            ..Default::default()
192        }
193        .from_env();
194        assert!(configured.enabled);
195        assert!(configured.allow_insecure);
196
197        env::set_var(ENV_MINT_MANAGEMENT_ENABLED_LEGACY, "true");
198        for value in ["false", "invalid"] {
199            env::set_var(ENV_MINT_MANAGEMENT_ENABLED, value);
200            assert!(!MintManagementRpc::default().from_env().enabled);
201        }
202        clear_env_vars();
203    }
204
205    #[cfg(unix)]
206    #[test]
207    fn management_rpc_non_unicode_overrides_fail_closed() {
208        use std::os::unix::ffi::OsStringExt;
209
210        let _guard = env_lock();
211        clear_env_vars();
212        env::set_var(ENV_MINT_MANAGEMENT_ENABLED_LEGACY, "true");
213        for name in [
214            ENV_MINT_MANAGEMENT_ENABLED,
215            ENV_MINT_MANAGEMENT_ALLOW_INSECURE,
216        ] {
217            env::set_var(name, std::ffi::OsString::from_vec(vec![0xff]));
218        }
219        let config = MintManagementRpc {
220            enabled: true,
221            allow_insecure: true,
222            ..Default::default()
223        }
224        .from_env();
225        assert!(!config.enabled);
226        assert!(!config.allow_insecure);
227        clear_env_vars();
228    }
229
230    #[test]
231    fn management_rpc_payment_override_env_fails_closed() {
232        let _guard = env_lock();
233        clear_env_vars();
234        let management_rpc = MintManagementRpc {
235            allow_mint_quote_payment_override: true,
236            ..Default::default()
237        };
238
239        env::set_var(
240            ENV_MINT_MANAGEMENT_ALLOW_MINT_QUOTE_PAYMENT_OVERRIDE,
241            "false",
242        );
243        assert!(
244            !management_rpc
245                .clone()
246                .from_env()
247                .allow_mint_quote_payment_override
248        );
249
250        env::set_var(
251            ENV_MINT_MANAGEMENT_ALLOW_MINT_QUOTE_PAYMENT_OVERRIDE,
252            "not-a-boolean",
253        );
254        assert!(!management_rpc.from_env().allow_mint_quote_payment_override);
255
256        clear_env_vars();
257    }
258}