platform_core/runtime_config/
generated.rs1use crate::db::DbPool;
2use crate::error::AppResult;
3use crate::runtime_config::descriptor::{
4 RuntimeConfigGeneratedValue, RuntimeConfigRegistry, RuntimeConfigVisibilityCondition,
5};
6use crate::runtime_config::snapshot::RuntimeConfigSnapshot;
7use crate::runtime_config::store::upsert_value_if_missing;
8use serde_json::Value;
9use std::collections::BTreeMap;
10use std::fmt::Write as _;
11
12pub async fn initialize_generated_values(
15 pool: &DbPool,
16 registry: &RuntimeConfigRegistry,
17 service_key: &str,
18 stored: &BTreeMap<(String, String), Value>,
19 actor: Option<&str>,
20) -> AppResult<Vec<(String, String)>> {
21 let snapshot = RuntimeConfigSnapshot::resolve(registry, service_key, stored);
22 let mut generated = Vec::new();
23 for descriptor in registry.iter() {
24 let descriptor_service = descriptor.scope.as_service_key();
25 if descriptor_service != "*" && descriptor_service != service_key {
26 continue;
27 }
28 let Some(RuntimeConfigGeneratedValue::Secret { bytes, when }) = &descriptor.generated
29 else {
30 continue;
31 };
32 if !condition_matches(when, service_key, &snapshot) {
33 continue;
34 }
35 let value = serde_json::json!(generate_secret(*bytes));
36 if upsert_value_if_missing(pool, descriptor_service, &descriptor.key, &value, actor)
37 .await?
38 .is_some()
39 {
40 generated.push((descriptor_service.to_owned(), descriptor.key.to_owned()));
41 }
42 }
43 Ok(generated)
44}
45
46fn condition_matches(
47 condition: &RuntimeConfigVisibilityCondition,
48 service_key: &str,
49 snapshot: &RuntimeConfigSnapshot,
50) -> bool {
51 match condition {
52 RuntimeConfigVisibilityCondition::Equals {
53 service,
54 key,
55 value,
56 } if *service == "*" || *service == service_key => {
57 snapshot.raw(key).is_some_and(|current| current == value)
58 }
59 RuntimeConfigVisibilityCondition::Equals { .. } => false,
60 }
61}
62
63fn generate_secret(bytes: usize) -> String {
64 let mut raw = vec![0_u8; bytes];
65 getrandom::fill(&mut raw).expect("OS randomness should be available");
66 let mut out = String::with_capacity(bytes * 2);
67 for byte in raw {
68 let _ = write!(&mut out, "{byte:02x}");
69 }
70 out
71}