1#[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_PROVIDER_STATE_PATH",
66 EnvClassification::KeepEnv,
67 RuntimePlacement::HostOnly,
68 None,
69 LegacyBehavior::Advanced,
70 false,
71 None,
72 ),
73 spec(
74 "SOMA_GRADUATION_ROOT",
75 EnvClassification::KeepEnv,
76 RuntimePlacement::HostOnly,
77 None,
78 LegacyBehavior::Advanced,
79 false,
80 None,
81 ),
82 spec(
83 "SOMA_PYTHON_BROKER_ALLOWED_PROVIDERS",
84 EnvClassification::KeepEnv,
85 RuntimePlacement::HostOnly,
86 Some("python.broker_allowed_providers"),
87 LegacyBehavior::Advanced,
88 false,
89 None,
90 ),
91 spec(
92 "SOMA_PYTHON_BROKER_ALLOWED_HTTP_HOSTS",
93 EnvClassification::KeepEnv,
94 RuntimePlacement::HostOnly,
95 Some("python.broker_allowed_http_hosts"),
96 LegacyBehavior::Advanced,
97 false,
98 None,
99 ),
100 spec(
101 "SOMA_PYTHON_BROKER_SECRET_NAMES",
102 EnvClassification::KeepEnv,
103 RuntimePlacement::HostOnly,
104 Some("python.broker_secret_names"),
105 LegacyBehavior::Advanced,
106 false,
107 None,
108 ),
109 spec(
110 "SOMA_PYTHON_BROKER_STATE_NAMESPACES",
111 EnvClassification::KeepEnv,
112 RuntimePlacement::HostOnly,
113 Some("python.broker_state_namespaces"),
114 LegacyBehavior::Advanced,
115 false,
116 None,
117 ),
118 spec(
119 "SOMA_PYTHON_BROKER_ALLOW_LOGGING",
120 EnvClassification::KeepEnv,
121 RuntimePlacement::HostOnly,
122 Some("python.broker_allow_logging"),
123 LegacyBehavior::Advanced,
124 false,
125 None,
126 ),
127 spec(
128 "SOMA_PYTHON_BROKER_ALLOW_METRICS",
129 EnvClassification::KeepEnv,
130 RuntimePlacement::HostOnly,
131 Some("python.broker_allow_metrics"),
132 LegacyBehavior::Advanced,
133 false,
134 None,
135 ),
136 spec(
137 "SOMA_PYTHON_BROKER_ALLOW_PROGRESS",
138 EnvClassification::KeepEnv,
139 RuntimePlacement::HostOnly,
140 Some("python.broker_allow_progress"),
141 LegacyBehavior::Advanced,
142 false,
143 None,
144 ),
145 spec(
146 "SOMA_PYTHON_BROKER_CGROUP_ROOT",
147 EnvClassification::KeepEnv,
148 RuntimePlacement::HostOnly,
149 None,
150 LegacyBehavior::Advanced,
151 false,
152 None,
153 ),
154 spec(
155 "SOMA_PYTHON_EXECUTION_PROFILE",
156 EnvClassification::KeepEnv,
157 RuntimePlacement::HostOnly,
158 Some("python.execution_profile"),
159 LegacyBehavior::Advanced,
160 false,
161 None,
162 ),
163 spec(
164 "SOMA_API_URL",
165 EnvClassification::KeepEnv,
166 RuntimePlacement::HostOnly,
167 Some("soma.api_url"),
168 LegacyBehavior::Canonical,
169 false,
170 Some("CLAUDE_PLUGIN_OPTION_SOMA_API_URL"),
171 ),
172 spec(
173 "SOMA_API_KEY",
174 EnvClassification::KeepEnv,
175 RuntimePlacement::HostOnly,
176 Some("soma.api_key"),
177 LegacyBehavior::Canonical,
178 true,
179 Some("CLAUDE_PLUGIN_OPTION_SOMA_API_KEY"),
180 ),
181 spec(
182 "SOMA_PYTHON_ENVIRONMENT_ENABLED",
183 EnvClassification::KeepEnv,
184 RuntimePlacement::HostOnly,
185 Some("python.environment.enabled"),
186 LegacyBehavior::Advanced,
187 false,
188 None,
189 ),
190 spec(
191 "SOMA_PYTHON_ENVIRONMENT_CACHE_ROOT",
192 EnvClassification::KeepEnv,
193 RuntimePlacement::HostOnly,
194 Some("python.environment.cache_root"),
195 LegacyBehavior::Advanced,
196 false,
197 None,
198 ),
199 spec(
200 "SOMA_PYTHON_ENVIRONMENT_UV_PROGRAM",
201 EnvClassification::KeepEnv,
202 RuntimePlacement::HostOnly,
203 Some("python.environment.uv_program"),
204 LegacyBehavior::Advanced,
205 false,
206 None,
207 ),
208 spec(
209 "SOMA_PYTHON_ENVIRONMENT_UV_VERSION",
210 EnvClassification::KeepEnv,
211 RuntimePlacement::HostOnly,
212 Some("python.environment.uv_version"),
213 LegacyBehavior::Advanced,
214 false,
215 None,
216 ),
217 spec(
218 "SOMA_PYTHON_ENVIRONMENT_PYTHON_EXECUTABLE",
219 EnvClassification::KeepEnv,
220 RuntimePlacement::HostOnly,
221 Some("python.environment.python_executable"),
222 LegacyBehavior::Advanced,
223 false,
224 None,
225 ),
226 spec(
227 "SOMA_PYTHON_ENVIRONMENT_RUNTIME_IMPLEMENTATION",
228 EnvClassification::KeepEnv,
229 RuntimePlacement::HostOnly,
230 Some("python.environment.runtime_implementation"),
231 LegacyBehavior::Advanced,
232 false,
233 None,
234 ),
235 spec(
236 "SOMA_PYTHON_ENVIRONMENT_RUNTIME_VERSION",
237 EnvClassification::KeepEnv,
238 RuntimePlacement::HostOnly,
239 Some("python.environment.runtime_version"),
240 LegacyBehavior::Advanced,
241 false,
242 None,
243 ),
244 spec(
245 "SOMA_PYTHON_ENVIRONMENT_RUNTIME_PLATFORM",
246 EnvClassification::KeepEnv,
247 RuntimePlacement::HostOnly,
248 Some("python.environment.runtime_platform"),
249 LegacyBehavior::Advanced,
250 false,
251 None,
252 ),
253 spec(
254 "SOMA_PYTHON_ENVIRONMENT_WHEEL_PLATFORM_TAG",
255 EnvClassification::KeepEnv,
256 RuntimePlacement::HostOnly,
257 Some("python.environment.wheel_platform_tag"),
258 LegacyBehavior::Advanced,
259 false,
260 None,
261 ),
262 spec(
263 "SOMA_PYTHON_ENVIRONMENT_SDK_WHEEL",
264 EnvClassification::KeepEnv,
265 RuntimePlacement::HostOnly,
266 Some("python.environment.sdk_wheel"),
267 LegacyBehavior::Advanced,
268 false,
269 None,
270 ),
271 spec(
272 "SOMA_PYTHON_ENVIRONMENT_SDK_WHEEL_SHA256",
273 EnvClassification::KeepEnv,
274 RuntimePlacement::HostOnly,
275 Some("python.environment.sdk_wheel_sha256"),
276 LegacyBehavior::Advanced,
277 false,
278 None,
279 ),
280 spec(
281 "SOMA_PYTHON_ENVIRONMENT_OFFLINE",
282 EnvClassification::KeepEnv,
283 RuntimePlacement::HostOnly,
284 Some("python.environment.offline"),
285 LegacyBehavior::Advanced,
286 false,
287 None,
288 ),
289 spec(
290 "SOMA_PYTHON_ENVIRONMENT_UPDATE",
291 EnvClassification::KeepEnv,
292 RuntimePlacement::HostOnly,
293 Some("python.environment.update"),
294 LegacyBehavior::Advanced,
295 false,
296 None,
297 ),
298 spec(
299 "SOMA_PYTHON_ENVIRONMENT_POLICY_VERSION",
300 EnvClassification::KeepEnv,
301 RuntimePlacement::HostOnly,
302 Some("python.environment.policy_version"),
303 LegacyBehavior::Advanced,
304 false,
305 None,
306 ),
307 spec(
308 "SOMA_MCP_TOKEN",
309 EnvClassification::TrustedOperatorBootstrap,
310 RuntimePlacement::Both,
311 Some("mcp.api_token"),
312 LegacyBehavior::Canonical,
313 true,
314 Some("CLAUDE_PLUGIN_OPTION_API_TOKEN"),
315 ),
316 spec(
317 "SOMA_SERVER_URL",
318 EnvClassification::KeepEnv,
319 RuntimePlacement::HostOnly,
320 None,
321 LegacyBehavior::WarnEnvOverride,
322 false,
323 Some("CLAUDE_PLUGIN_OPTION_SERVER_URL"),
324 ),
325 spec(
326 "SOMA_MCP_AUTH_MODE",
327 EnvClassification::KeepEnv,
328 RuntimePlacement::Both,
329 Some("mcp.auth.mode"),
330 LegacyBehavior::Canonical,
331 false,
332 Some("CLAUDE_PLUGIN_OPTION_AUTH_MODE"),
333 ),
334 spec(
335 "SOMA_MCP_NO_AUTH",
336 EnvClassification::TrustedOperatorBootstrap,
337 RuntimePlacement::HostOnly,
338 Some("mcp.no_auth"),
339 LegacyBehavior::Advanced,
340 false,
341 Some("CLAUDE_PLUGIN_OPTION_NO_AUTH"),
342 ),
343 spec(
344 "SOMA_NOAUTH",
345 EnvClassification::TrustedOperatorBootstrap,
346 RuntimePlacement::Both,
347 Some("mcp.trusted_gateway"),
348 LegacyBehavior::Advanced,
349 false,
350 None,
351 ),
352 spec(
353 "SOMA_MCP_PUBLIC_URL",
354 EnvClassification::KeepEnv,
355 RuntimePlacement::Both,
356 Some("mcp.auth.public_url"),
357 LegacyBehavior::Canonical,
358 false,
359 Some("CLAUDE_PLUGIN_OPTION_PUBLIC_URL"),
360 ),
361 spec(
362 "SOMA_MCP_GOOGLE_CLIENT_ID",
363 EnvClassification::TrustedOperatorBootstrap,
364 RuntimePlacement::Both,
365 Some("mcp.auth.google_client_id"),
366 LegacyBehavior::Canonical,
367 true,
368 Some("CLAUDE_PLUGIN_OPTION_GOOGLE_CLIENT_ID"),
369 ),
370 spec(
371 "SOMA_MCP_GOOGLE_CLIENT_SECRET",
372 EnvClassification::TrustedOperatorBootstrap,
373 RuntimePlacement::Both,
374 Some("mcp.auth.google_client_secret"),
375 LegacyBehavior::Canonical,
376 true,
377 Some("CLAUDE_PLUGIN_OPTION_GOOGLE_CLIENT_SECRET"),
378 ),
379 spec(
380 "SOMA_MCP_GOOGLE_CALLBACK_PATH",
381 EnvClassification::TrustedOperatorBootstrap,
382 RuntimePlacement::Both,
383 Some("mcp.auth.google_callback_path"),
384 LegacyBehavior::Canonical,
385 false,
386 None,
387 ),
388 spec(
389 "SOMA_MCP_GOOGLE_SCOPES",
390 EnvClassification::TrustedOperatorBootstrap,
391 RuntimePlacement::Both,
392 Some("mcp.auth.google_scopes"),
393 LegacyBehavior::Canonical,
394 false,
395 None,
396 ),
397 spec(
398 "SOMA_MCP_AUTHELIA_ISSUER_URL",
399 EnvClassification::TrustedOperatorBootstrap,
400 RuntimePlacement::Both,
401 Some("mcp.auth.authelia_issuer_url"),
402 LegacyBehavior::Canonical,
403 false,
404 None,
405 ),
406 spec(
407 "SOMA_MCP_AUTHELIA_CLIENT_ID",
408 EnvClassification::TrustedOperatorBootstrap,
409 RuntimePlacement::Both,
410 Some("mcp.auth.authelia_client_id"),
411 LegacyBehavior::Canonical,
412 true,
413 None,
414 ),
415 spec(
416 "SOMA_MCP_AUTHELIA_CLIENT_SECRET",
417 EnvClassification::TrustedOperatorBootstrap,
418 RuntimePlacement::Both,
419 Some("mcp.auth.authelia_client_secret"),
420 LegacyBehavior::Canonical,
421 true,
422 None,
423 ),
424 spec(
425 "SOMA_MCP_AUTHELIA_CALLBACK_PATH",
426 EnvClassification::TrustedOperatorBootstrap,
427 RuntimePlacement::Both,
428 Some("mcp.auth.authelia_callback_path"),
429 LegacyBehavior::Canonical,
430 false,
431 None,
432 ),
433 spec(
434 "SOMA_MCP_AUTHELIA_SCOPES",
435 EnvClassification::TrustedOperatorBootstrap,
436 RuntimePlacement::Both,
437 Some("mcp.auth.authelia_scopes"),
438 LegacyBehavior::Canonical,
439 false,
440 None,
441 ),
442 spec(
443 "SOMA_MCP_GITHUB_CLIENT_ID",
444 EnvClassification::TrustedOperatorBootstrap,
445 RuntimePlacement::Both,
446 Some("mcp.auth.github_client_id"),
447 LegacyBehavior::Canonical,
448 true,
449 None,
450 ),
451 spec(
452 "SOMA_MCP_GITHUB_CLIENT_SECRET",
453 EnvClassification::TrustedOperatorBootstrap,
454 RuntimePlacement::Both,
455 Some("mcp.auth.github_client_secret"),
456 LegacyBehavior::Canonical,
457 true,
458 None,
459 ),
460 spec(
461 "SOMA_MCP_GITHUB_CALLBACK_PATH",
462 EnvClassification::TrustedOperatorBootstrap,
463 RuntimePlacement::Both,
464 Some("mcp.auth.github_callback_path"),
465 LegacyBehavior::Canonical,
466 false,
467 None,
468 ),
469 spec(
470 "SOMA_MCP_GITHUB_SCOPES",
471 EnvClassification::TrustedOperatorBootstrap,
472 RuntimePlacement::Both,
473 Some("mcp.auth.github_scopes"),
474 LegacyBehavior::Canonical,
475 false,
476 None,
477 ),
478 spec(
479 "SOMA_MCP_AUTH_DEFAULT_PROVIDER",
480 EnvClassification::TrustedOperatorBootstrap,
481 RuntimePlacement::Both,
482 Some("mcp.auth.default_provider"),
483 LegacyBehavior::Canonical,
484 false,
485 None,
486 ),
487 spec(
488 "SOMA_MCP_AUTH_ADMIN_EMAIL",
489 EnvClassification::TrustedOperatorBootstrap,
490 RuntimePlacement::Both,
491 Some("mcp.auth.admin_email"),
492 LegacyBehavior::Canonical,
493 false,
494 Some("CLAUDE_PLUGIN_OPTION_AUTH_ADMIN_EMAIL"),
495 ),
496 spec(
497 "SOMA_MCP_HOST",
498 EnvClassification::ComposeEnv,
499 RuntimePlacement::Both,
500 Some("mcp.host"),
501 LegacyBehavior::Canonical,
502 false,
503 None,
504 ),
505 spec(
506 "SOMA_MCP_SERVER_NAME",
507 EnvClassification::ComposeEnv,
508 RuntimePlacement::Both,
509 Some("mcp.server_name"),
510 LegacyBehavior::Canonical,
511 false,
512 None,
513 ),
514 spec(
515 "SOMA_MCP_PORT",
516 EnvClassification::ComposeEnv,
517 RuntimePlacement::Both,
518 Some("mcp.port"),
519 LegacyBehavior::Canonical,
520 false,
521 None,
522 ),
523 spec(
524 "SOMA_MCP_ALLOWED_HOSTS",
525 EnvClassification::ComposeEnv,
526 RuntimePlacement::Both,
527 Some("mcp.allowed_hosts"),
528 LegacyBehavior::Canonical,
529 false,
530 None,
531 ),
532 spec(
533 "SOMA_MCP_ALLOWED_ORIGINS",
534 EnvClassification::ComposeEnv,
535 RuntimePlacement::Both,
536 Some("mcp.allowed_origins"),
537 LegacyBehavior::Canonical,
538 false,
539 None,
540 ),
541 spec(
542 "SOMA_MCP_TRACE_HEADERS",
543 EnvClassification::KeepEnv,
544 RuntimePlacement::Both,
545 Some("mcp.trace_headers"),
546 LegacyBehavior::Canonical,
547 false,
548 Some("CLAUDE_PLUGIN_OPTION_TRACE_HEADERS"),
549 ),
550 spec(
551 "SOMA_MCP_STATIC_TOKEN_WRITE",
552 EnvClassification::TrustedOperatorBootstrap,
553 RuntimePlacement::Both,
554 Some("mcp.static_token_write"),
555 LegacyBehavior::Advanced,
556 false,
557 None,
558 ),
559 spec(
560 "SOMA_MCP_AUTH_BOOTSTRAP_SECRET",
561 EnvClassification::TrustedOperatorBootstrap,
562 RuntimePlacement::Both,
563 Some("mcp.auth.bootstrap_secret"),
564 LegacyBehavior::Canonical,
565 true,
566 None,
567 ),
568 spec(
569 "SOMA_MCP_AUTH_SQLITE_PATH",
570 EnvClassification::TrustedOperatorBootstrap,
571 RuntimePlacement::Both,
572 Some("mcp.auth.sqlite_path"),
573 LegacyBehavior::Canonical,
574 false,
575 None,
576 ),
577 spec(
578 "SOMA_MCP_AUTH_KEY_PATH",
579 EnvClassification::TrustedOperatorBootstrap,
580 RuntimePlacement::Both,
581 Some("mcp.auth.key_path"),
582 LegacyBehavior::Canonical,
583 false,
584 None,
585 ),
586 spec(
587 "SOMA_MCP_AUTH_ACCESS_TOKEN_TTL_SECS",
588 EnvClassification::TrustedOperatorBootstrap,
589 RuntimePlacement::Both,
590 Some("mcp.auth.access_token_ttl_secs"),
591 LegacyBehavior::Canonical,
592 false,
593 None,
594 ),
595 spec(
596 "SOMA_MCP_AUTH_REFRESH_TOKEN_TTL_SECS",
597 EnvClassification::TrustedOperatorBootstrap,
598 RuntimePlacement::Both,
599 Some("mcp.auth.refresh_token_ttl_secs"),
600 LegacyBehavior::Canonical,
601 false,
602 None,
603 ),
604 spec(
605 "SOMA_MCP_AUTH_CODE_TTL_SECS",
606 EnvClassification::TrustedOperatorBootstrap,
607 RuntimePlacement::Both,
608 Some("mcp.auth.auth_code_ttl_secs"),
609 LegacyBehavior::Canonical,
610 false,
611 None,
612 ),
613 spec(
614 "SOMA_MCP_AUTH_REGISTER_REQUESTS_PER_MINUTE",
615 EnvClassification::TrustedOperatorBootstrap,
616 RuntimePlacement::Both,
617 Some("mcp.auth.register_rpm"),
618 LegacyBehavior::Canonical,
619 false,
620 None,
621 ),
622 spec(
623 "SOMA_MCP_AUTH_AUTHORIZE_REQUESTS_PER_MINUTE",
624 EnvClassification::TrustedOperatorBootstrap,
625 RuntimePlacement::Both,
626 Some("mcp.auth.authorize_rpm"),
627 LegacyBehavior::Canonical,
628 false,
629 None,
630 ),
631 spec(
632 "SOMA_MCP_AUTH_MAX_PENDING_OAUTH_STATES",
633 EnvClassification::TrustedOperatorBootstrap,
634 RuntimePlacement::Both,
635 Some("mcp.auth.max_pending_oauth_states"),
636 LegacyBehavior::Canonical,
637 false,
638 None,
639 ),
640 spec(
641 "SOMA_MCP_AUTH_ALLOWED_REDIRECT_URIS",
642 EnvClassification::TrustedOperatorBootstrap,
643 RuntimePlacement::Both,
644 Some("mcp.auth.allowed_client_redirect_uris"),
645 LegacyBehavior::Canonical,
646 false,
647 None,
648 ),
649 spec(
650 "SOMA_MCP_TOKEN_ENCRYPTION_KEY",
651 EnvClassification::TrustedOperatorBootstrap,
652 RuntimePlacement::Both,
653 Some("mcp.auth.token_encryption_key"),
654 LegacyBehavior::Canonical,
655 true,
656 None,
657 ),
658];
659
660pub fn all_specs() -> &'static [EnvKeySpec] {
661 ENV_KEY_SPECS
662}
663
664pub fn spec_for(key: &str) -> Option<&'static EnvKeySpec> {
665 ENV_KEY_SPECS.iter().find(|spec| spec.key == key)
666}
667
668pub fn plugin_option_mappings() -> impl Iterator<Item = (&'static str, &'static str)> {
669 ENV_KEY_SPECS
670 .iter()
671 .filter_map(|spec| spec.plugin_option.map(|option| (option, spec.key)))
672}