Skip to main content

soma_config/
env_registry.rs

1//! Canonical environment-variable registry.
2//!
3//! Keep setup, docs, and plugin option mapping pointed at this table instead of
4//! scattering env-var knowledge across shell snippets and manifests.
5
6#[cfg(test)]
7#[path = "env_registry_tests.rs"]
8mod tests;
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq)]
11pub enum EnvClassification {
12    KeepEnv,
13    ComposeEnv,
14    TrustedOperatorBootstrap,
15}
16
17#[derive(Debug, Clone, Copy, PartialEq, Eq)]
18pub enum RuntimePlacement {
19    HostOnly,
20    ContainerRequired,
21    ComposeInterpolation,
22    Both,
23}
24
25#[derive(Debug, Clone, Copy, PartialEq, Eq)]
26pub enum LegacyBehavior {
27    Canonical,
28    WarnEnvOverride,
29    Advanced,
30}
31
32#[derive(Debug, Clone, Copy, PartialEq, Eq)]
33pub struct EnvKeySpec {
34    pub key: &'static str,
35    pub classification: EnvClassification,
36    pub placement: RuntimePlacement,
37    pub toml_destination: Option<&'static str>,
38    pub legacy_behavior: LegacyBehavior,
39    pub secret: bool,
40    pub plugin_option: Option<&'static str>,
41}
42
43pub const fn spec(
44    key: &'static str,
45    classification: EnvClassification,
46    placement: RuntimePlacement,
47    toml_destination: Option<&'static str>,
48    legacy_behavior: LegacyBehavior,
49    secret: bool,
50    plugin_option: Option<&'static str>,
51) -> EnvKeySpec {
52    EnvKeySpec {
53        key,
54        classification,
55        placement,
56        toml_destination,
57        legacy_behavior,
58        secret,
59        plugin_option,
60    }
61}
62
63pub const ENV_KEY_SPECS: &[EnvKeySpec] = &[
64    spec(
65        "SOMA_API_URL",
66        EnvClassification::KeepEnv,
67        RuntimePlacement::HostOnly,
68        Some("soma.api_url"),
69        LegacyBehavior::Canonical,
70        false,
71        Some("CLAUDE_PLUGIN_OPTION_SOMA_API_URL"),
72    ),
73    spec(
74        "SOMA_API_KEY",
75        EnvClassification::KeepEnv,
76        RuntimePlacement::HostOnly,
77        Some("soma.api_key"),
78        LegacyBehavior::Canonical,
79        true,
80        Some("CLAUDE_PLUGIN_OPTION_SOMA_API_KEY"),
81    ),
82    spec(
83        "SOMA_MCP_TOKEN",
84        EnvClassification::TrustedOperatorBootstrap,
85        RuntimePlacement::Both,
86        Some("mcp.api_token"),
87        LegacyBehavior::Canonical,
88        true,
89        Some("CLAUDE_PLUGIN_OPTION_API_TOKEN"),
90    ),
91    spec(
92        "SOMA_SERVER_URL",
93        EnvClassification::KeepEnv,
94        RuntimePlacement::HostOnly,
95        None,
96        LegacyBehavior::WarnEnvOverride,
97        false,
98        Some("CLAUDE_PLUGIN_OPTION_SERVER_URL"),
99    ),
100    spec(
101        "SOMA_MCP_AUTH_MODE",
102        EnvClassification::KeepEnv,
103        RuntimePlacement::Both,
104        Some("mcp.auth.mode"),
105        LegacyBehavior::Canonical,
106        false,
107        Some("CLAUDE_PLUGIN_OPTION_AUTH_MODE"),
108    ),
109    spec(
110        "SOMA_MCP_NO_AUTH",
111        EnvClassification::TrustedOperatorBootstrap,
112        RuntimePlacement::HostOnly,
113        Some("mcp.no_auth"),
114        LegacyBehavior::Advanced,
115        false,
116        Some("CLAUDE_PLUGIN_OPTION_NO_AUTH"),
117    ),
118    spec(
119        "SOMA_NOAUTH",
120        EnvClassification::TrustedOperatorBootstrap,
121        RuntimePlacement::Both,
122        Some("mcp.trusted_gateway"),
123        LegacyBehavior::Advanced,
124        false,
125        None,
126    ),
127    spec(
128        "SOMA_MCP_PUBLIC_URL",
129        EnvClassification::KeepEnv,
130        RuntimePlacement::Both,
131        Some("mcp.auth.public_url"),
132        LegacyBehavior::Canonical,
133        false,
134        Some("CLAUDE_PLUGIN_OPTION_PUBLIC_URL"),
135    ),
136    spec(
137        "SOMA_MCP_GOOGLE_CLIENT_ID",
138        EnvClassification::TrustedOperatorBootstrap,
139        RuntimePlacement::Both,
140        Some("mcp.auth.google_client_id"),
141        LegacyBehavior::Canonical,
142        true,
143        Some("CLAUDE_PLUGIN_OPTION_GOOGLE_CLIENT_ID"),
144    ),
145    spec(
146        "SOMA_MCP_GOOGLE_CLIENT_SECRET",
147        EnvClassification::TrustedOperatorBootstrap,
148        RuntimePlacement::Both,
149        Some("mcp.auth.google_client_secret"),
150        LegacyBehavior::Canonical,
151        true,
152        Some("CLAUDE_PLUGIN_OPTION_GOOGLE_CLIENT_SECRET"),
153    ),
154    spec(
155        "SOMA_MCP_GOOGLE_CALLBACK_PATH",
156        EnvClassification::TrustedOperatorBootstrap,
157        RuntimePlacement::Both,
158        Some("mcp.auth.google_callback_path"),
159        LegacyBehavior::Canonical,
160        false,
161        None,
162    ),
163    spec(
164        "SOMA_MCP_GOOGLE_SCOPES",
165        EnvClassification::TrustedOperatorBootstrap,
166        RuntimePlacement::Both,
167        Some("mcp.auth.google_scopes"),
168        LegacyBehavior::Canonical,
169        false,
170        None,
171    ),
172    spec(
173        "SOMA_MCP_AUTHELIA_ISSUER_URL",
174        EnvClassification::TrustedOperatorBootstrap,
175        RuntimePlacement::Both,
176        Some("mcp.auth.authelia_issuer_url"),
177        LegacyBehavior::Canonical,
178        false,
179        None,
180    ),
181    spec(
182        "SOMA_MCP_AUTHELIA_CLIENT_ID",
183        EnvClassification::TrustedOperatorBootstrap,
184        RuntimePlacement::Both,
185        Some("mcp.auth.authelia_client_id"),
186        LegacyBehavior::Canonical,
187        true,
188        None,
189    ),
190    spec(
191        "SOMA_MCP_AUTHELIA_CLIENT_SECRET",
192        EnvClassification::TrustedOperatorBootstrap,
193        RuntimePlacement::Both,
194        Some("mcp.auth.authelia_client_secret"),
195        LegacyBehavior::Canonical,
196        true,
197        None,
198    ),
199    spec(
200        "SOMA_MCP_AUTHELIA_CALLBACK_PATH",
201        EnvClassification::TrustedOperatorBootstrap,
202        RuntimePlacement::Both,
203        Some("mcp.auth.authelia_callback_path"),
204        LegacyBehavior::Canonical,
205        false,
206        None,
207    ),
208    spec(
209        "SOMA_MCP_AUTHELIA_SCOPES",
210        EnvClassification::TrustedOperatorBootstrap,
211        RuntimePlacement::Both,
212        Some("mcp.auth.authelia_scopes"),
213        LegacyBehavior::Canonical,
214        false,
215        None,
216    ),
217    spec(
218        "SOMA_MCP_GITHUB_CLIENT_ID",
219        EnvClassification::TrustedOperatorBootstrap,
220        RuntimePlacement::Both,
221        Some("mcp.auth.github_client_id"),
222        LegacyBehavior::Canonical,
223        true,
224        None,
225    ),
226    spec(
227        "SOMA_MCP_GITHUB_CLIENT_SECRET",
228        EnvClassification::TrustedOperatorBootstrap,
229        RuntimePlacement::Both,
230        Some("mcp.auth.github_client_secret"),
231        LegacyBehavior::Canonical,
232        true,
233        None,
234    ),
235    spec(
236        "SOMA_MCP_GITHUB_CALLBACK_PATH",
237        EnvClassification::TrustedOperatorBootstrap,
238        RuntimePlacement::Both,
239        Some("mcp.auth.github_callback_path"),
240        LegacyBehavior::Canonical,
241        false,
242        None,
243    ),
244    spec(
245        "SOMA_MCP_GITHUB_SCOPES",
246        EnvClassification::TrustedOperatorBootstrap,
247        RuntimePlacement::Both,
248        Some("mcp.auth.github_scopes"),
249        LegacyBehavior::Canonical,
250        false,
251        None,
252    ),
253    spec(
254        "SOMA_MCP_AUTH_DEFAULT_PROVIDER",
255        EnvClassification::TrustedOperatorBootstrap,
256        RuntimePlacement::Both,
257        Some("mcp.auth.default_provider"),
258        LegacyBehavior::Canonical,
259        false,
260        None,
261    ),
262    spec(
263        "SOMA_MCP_AUTH_ADMIN_EMAIL",
264        EnvClassification::TrustedOperatorBootstrap,
265        RuntimePlacement::Both,
266        Some("mcp.auth.admin_email"),
267        LegacyBehavior::Canonical,
268        false,
269        Some("CLAUDE_PLUGIN_OPTION_AUTH_ADMIN_EMAIL"),
270    ),
271    spec(
272        "SOMA_MCP_HOST",
273        EnvClassification::ComposeEnv,
274        RuntimePlacement::Both,
275        Some("mcp.host"),
276        LegacyBehavior::Canonical,
277        false,
278        None,
279    ),
280    spec(
281        "SOMA_MCP_SERVER_NAME",
282        EnvClassification::ComposeEnv,
283        RuntimePlacement::Both,
284        Some("mcp.server_name"),
285        LegacyBehavior::Canonical,
286        false,
287        None,
288    ),
289    spec(
290        "SOMA_MCP_PORT",
291        EnvClassification::ComposeEnv,
292        RuntimePlacement::Both,
293        Some("mcp.port"),
294        LegacyBehavior::Canonical,
295        false,
296        None,
297    ),
298    spec(
299        "SOMA_MCP_ALLOWED_HOSTS",
300        EnvClassification::ComposeEnv,
301        RuntimePlacement::Both,
302        Some("mcp.allowed_hosts"),
303        LegacyBehavior::Canonical,
304        false,
305        None,
306    ),
307    spec(
308        "SOMA_MCP_ALLOWED_ORIGINS",
309        EnvClassification::ComposeEnv,
310        RuntimePlacement::Both,
311        Some("mcp.allowed_origins"),
312        LegacyBehavior::Canonical,
313        false,
314        None,
315    ),
316    spec(
317        "SOMA_MCP_TRACE_HEADERS",
318        EnvClassification::KeepEnv,
319        RuntimePlacement::Both,
320        Some("mcp.trace_headers"),
321        LegacyBehavior::Canonical,
322        false,
323        Some("CLAUDE_PLUGIN_OPTION_TRACE_HEADERS"),
324    ),
325    spec(
326        "SOMA_MCP_STATIC_TOKEN_WRITE",
327        EnvClassification::TrustedOperatorBootstrap,
328        RuntimePlacement::Both,
329        Some("mcp.static_token_write"),
330        LegacyBehavior::Advanced,
331        false,
332        None,
333    ),
334    spec(
335        "SOMA_MCP_AUTH_BOOTSTRAP_SECRET",
336        EnvClassification::TrustedOperatorBootstrap,
337        RuntimePlacement::Both,
338        Some("mcp.auth.bootstrap_secret"),
339        LegacyBehavior::Canonical,
340        true,
341        None,
342    ),
343    spec(
344        "SOMA_MCP_AUTH_SQLITE_PATH",
345        EnvClassification::TrustedOperatorBootstrap,
346        RuntimePlacement::Both,
347        Some("mcp.auth.sqlite_path"),
348        LegacyBehavior::Canonical,
349        false,
350        None,
351    ),
352    spec(
353        "SOMA_MCP_AUTH_KEY_PATH",
354        EnvClassification::TrustedOperatorBootstrap,
355        RuntimePlacement::Both,
356        Some("mcp.auth.key_path"),
357        LegacyBehavior::Canonical,
358        false,
359        None,
360    ),
361    spec(
362        "SOMA_MCP_AUTH_ACCESS_TOKEN_TTL_SECS",
363        EnvClassification::TrustedOperatorBootstrap,
364        RuntimePlacement::Both,
365        Some("mcp.auth.access_token_ttl_secs"),
366        LegacyBehavior::Canonical,
367        false,
368        None,
369    ),
370    spec(
371        "SOMA_MCP_AUTH_REFRESH_TOKEN_TTL_SECS",
372        EnvClassification::TrustedOperatorBootstrap,
373        RuntimePlacement::Both,
374        Some("mcp.auth.refresh_token_ttl_secs"),
375        LegacyBehavior::Canonical,
376        false,
377        None,
378    ),
379    spec(
380        "SOMA_MCP_AUTH_CODE_TTL_SECS",
381        EnvClassification::TrustedOperatorBootstrap,
382        RuntimePlacement::Both,
383        Some("mcp.auth.auth_code_ttl_secs"),
384        LegacyBehavior::Canonical,
385        false,
386        None,
387    ),
388    spec(
389        "SOMA_MCP_AUTH_REGISTER_REQUESTS_PER_MINUTE",
390        EnvClassification::TrustedOperatorBootstrap,
391        RuntimePlacement::Both,
392        Some("mcp.auth.register_rpm"),
393        LegacyBehavior::Canonical,
394        false,
395        None,
396    ),
397    spec(
398        "SOMA_MCP_AUTH_AUTHORIZE_REQUESTS_PER_MINUTE",
399        EnvClassification::TrustedOperatorBootstrap,
400        RuntimePlacement::Both,
401        Some("mcp.auth.authorize_rpm"),
402        LegacyBehavior::Canonical,
403        false,
404        None,
405    ),
406    spec(
407        "SOMA_MCP_AUTH_MAX_PENDING_OAUTH_STATES",
408        EnvClassification::TrustedOperatorBootstrap,
409        RuntimePlacement::Both,
410        Some("mcp.auth.max_pending_oauth_states"),
411        LegacyBehavior::Canonical,
412        false,
413        None,
414    ),
415    spec(
416        "SOMA_MCP_AUTH_ALLOWED_REDIRECT_URIS",
417        EnvClassification::TrustedOperatorBootstrap,
418        RuntimePlacement::Both,
419        Some("mcp.auth.allowed_client_redirect_uris"),
420        LegacyBehavior::Canonical,
421        false,
422        None,
423    ),
424    spec(
425        "SOMA_MCP_TOKEN_ENCRYPTION_KEY",
426        EnvClassification::TrustedOperatorBootstrap,
427        RuntimePlacement::Both,
428        Some("mcp.auth.token_encryption_key"),
429        LegacyBehavior::Canonical,
430        true,
431        None,
432    ),
433];
434
435pub fn all_specs() -> &'static [EnvKeySpec] {
436    ENV_KEY_SPECS
437}
438
439pub fn spec_for(key: &str) -> Option<&'static EnvKeySpec> {
440    ENV_KEY_SPECS.iter().find(|spec| spec.key == key)
441}
442
443pub fn plugin_option_mappings() -> impl Iterator<Item = (&'static str, &'static str)> {
444    ENV_KEY_SPECS
445        .iter()
446        .filter_map(|spec| spec.plugin_option.map(|option| (option, spec.key)))
447}