tuwunel_core/config/regenerate/
overlay.rs1use std::sync::LazyLock;
2
3use figment::{
4 Figment, Profile, Provider, Source,
5 value::{Dict, Value},
6};
7use itertools::Itertools as _;
8use regex::RegexSet;
9
10use super::super::KNOWN_KEYS;
11use crate::{Err, Result, err};
12
13static NONCONFIG_KEYS: LazyLock<Result<RegexSet, regex::Error>> =
14 LazyLock::new(|| RegexSet::new(KNOWN_KEYS));
15
16pub(super) fn validate_file_overlay(figment: &Figment) -> Result {
17 let profiles = Provider::data(figment)?;
18 let unsupported = profiles
19 .iter()
20 .filter(|(profile, values)| {
21 !values.is_empty() && **profile != Profile::Default && **profile != Profile::Global
22 })
23 .map(|(profile, _)| profile.as_str())
24 .join(", ");
25
26 if !unsupported.is_empty() {
27 return Err!("Unsupported configuration profiles: {unsupported}.");
28 }
29
30 let valid = profiles
31 .values()
32 .flat_map(Dict::values)
33 .all(|value| file_tree(figment, value));
34
35 if !valid {
36 return Err!("The regeneration overlay contains a value not sourced from a file.");
37 }
38
39 Ok(())
40}
41
42fn file_tree(figment: &Figment, value: &Value) -> bool {
43 match value {
44 | Value::Dict(_, values) => values
45 .values()
46 .all(|value| file_tree(figment, value)),
47 | Value::Array(_, values) => values
48 .iter()
49 .all(|value| file_tree(figment, value)),
50 | _ => is_file_value(figment, value),
51 }
52}
53
54pub(super) fn is_file_value(figment: &Figment, value: &Value) -> bool {
55 figment
56 .get_metadata(value.tag())
57 .and_then(|metadata| metadata.source.as_ref())
58 .and_then(Source::file_path)
59 .is_some()
60}
61
62pub(super) fn filter_nonconfig_environment(figment: &Figment, values: &mut Dict) -> Result {
63 let known = NONCONFIG_KEYS
64 .as_ref()
65 .map_err(|error| err!("Invalid known configuration key expression: {error}"))?;
66
67 values.retain(|key, value| !known.is_match(key) || is_file_value(figment, value));
68
69 Ok(())
70}