micromegas_auth/env.rs
1//! Shared prefixed-env-var resolution, used by every `{prefix}_*`-with-fallback knob in this
2//! crate (`{prefix}_OIDC_CONFIG`, `{prefix}_DEFAULT_AUDIENCE`), and the three surviving
3//! `{prefix}_API_KEY_*CACHE*` knobs (`{prefix}_API_KEY_CACHE_SIZE`,
4//! `{prefix}_API_KEY_UNKNOWN_CACHE_TTL_SECONDS`, `{prefix}_API_KEY_UNKNOWN_CACHE_SIZE`).
5
6/// Resolves `{prefix}_{suffix}`, falling back to unprefixed `MICROMEGAS_{suffix}` when the
7/// prefixed name is unset, or always when `prefix` is empty.
8///
9/// `suffix` is passed **without** the `MICROMEGAS_` prefix (e.g. `"OIDC_CONFIG"`,
10/// `"DEFAULT_AUDIENCE"`).
11pub fn resolve_prefixed_var(prefix: &str, suffix: &str) -> String {
12 if prefix.is_empty() {
13 format!("MICROMEGAS_{suffix}")
14 } else {
15 let prefixed = format!("{prefix}_{suffix}");
16 if std::env::var(&prefixed).is_ok() {
17 prefixed
18 } else {
19 format!("MICROMEGAS_{suffix}")
20 }
21 }
22}
23
24/// Returns the subset of `removed` that is set to any value, empty string included. Pure
25/// detection, split out from the `warn_removed_*` wrappers so it is unit-testable without
26/// capturing a log sink. Not part of this crate's public API; `pub` only so the tests in
27/// `tests/env_tests.rs` can reach it.
28#[doc(hidden)]
29pub fn removed_vars_that_are_set(removed: &[&'static str]) -> Vec<&'static str> {
30 removed
31 .iter()
32 .copied()
33 .filter(|var| std::env::var(var).is_ok())
34 .collect()
35}
36
37/// Warns when any of the three removed env-var API-keyrings --
38/// `MICROMEGAS_API_KEYS`, `MICROMEGAS_INGESTION_API_KEYS`, `MICROMEGAS_ANALYTICS_API_KEYS` -- is
39/// still set. `ingestion_api_keys` / `analytics_api_keys` are the only sources from here on, and
40/// the keys they hold are minted there -- a still-set keyring's own key strings cannot be carried
41/// over, so every client presenting one needs a freshly minted key. Unlike the earlier
42/// removed-var families, this removal warns rather than refusing startup.
43pub(crate) fn warn_removed_api_key_vars() {
44 const REMOVED: [&str; 3] = [
45 "MICROMEGAS_API_KEYS",
46 "MICROMEGAS_INGESTION_API_KEYS",
47 "MICROMEGAS_ANALYTICS_API_KEYS",
48 ];
49 let set = removed_vars_that_are_set(&REMOVED);
50 if !set.is_empty() {
51 let api_keys_caveat = if set.contains(&"MICROMEGAS_API_KEYS") {
52 " on ingestion/flight-sql (`object-cache-srv` still requires it)"
53 } else {
54 ""
55 };
56 micromegas_tracing::warn!(
57 "{} {} set but no longer read -- mint replacement keys into ingestion_api_keys / \
58 analytics_api_keys from the web app's admin pages, redistribute them to the \
59 clients still presenting the old ones, then unset {}{}",
60 set.join(", "),
61 if set.len() == 1 { "is" } else { "are" },
62 if set.len() == 1 { "it" } else { "them" },
63 api_keys_caveat
64 );
65 }
66}
67
68/// Warns when either of the two removed env-var audience-grant maps --
69/// `MICROMEGAS_AUDIENCE_GRANTS`, `MICROMEGAS_ANALYTICS_AUDIENCE_GRANTS` -- is still set. The
70/// `audience_grants` table is the only source from here on; `micromegas-grants create <audience>
71/// <axis> <selector>` creates a grant row. `MICROMEGAS_INGESTION_AUDIENCE_GRANTS` is excluded --
72/// it was never read by any `AudienceReadPolicy::from_env` call, so warning about it would tell
73/// an operator they lost a setting that never did anything.
74pub(crate) fn warn_removed_audience_grant_vars() {
75 const REMOVED: [&str; 2] = [
76 "MICROMEGAS_AUDIENCE_GRANTS",
77 "MICROMEGAS_ANALYTICS_AUDIENCE_GRANTS",
78 ];
79 let set = removed_vars_that_are_set(&REMOVED);
80 if !set.is_empty() {
81 micromegas_tracing::warn!(
82 "{} {} set but no longer read -- create the grant with \
83 `micromegas-grants create <audience> <axis> <selector>`, then unset {}",
84 set.join(", "),
85 if set.len() == 1 { "is" } else { "are" },
86 if set.len() == 1 { "it" } else { "them" }
87 );
88 }
89}