greentic_dev/
secrets_seed.rs

1use std::collections::HashMap;
2use std::fs;
3use std::path::Path;
4
5use anyhow::{Context, Result, bail};
6use base64::Engine;
7use base64::engine::general_purpose::STANDARD as B64_STANDARD;
8use serde::Deserialize;
9use serde_json::Value as JsonValue;
10use serde_yaml_bw as serde_yaml;
11
12#[derive(Debug, Deserialize)]
13struct SeedDoc {
14    entries: Vec<SeedEntry>,
15}
16
17#[derive(Debug, Deserialize)]
18struct SeedEntry {
19    uri: String,
20    #[serde(default)]
21    text: Option<String>,
22    #[serde(default)]
23    json: Option<JsonValue>,
24    #[serde(default, rename = "bytes_b64")]
25    bytes_b64: Option<String>,
26    #[serde(default)]
27    value: Option<JsonValue>,
28}
29
30pub fn load_seed_file(path: &Path) -> Result<HashMap<String, Vec<u8>>> {
31    let data = fs::read_to_string(path)
32        .with_context(|| format!("failed to read secrets seed at {}", path.display()))?;
33    // Try canonical seed format first.
34    if let Ok(doc) = serde_yaml::from_str::<SeedDoc>(&data) {
35        let mut map = HashMap::new();
36        for entry in doc.entries {
37            let (uri, bytes) = seed_entry_to_bytes(entry)?;
38            map.insert(uri, bytes);
39        }
40        return Ok(map);
41    }
42    // Fallback: simple map of uri -> string/JSON value.
43    if let Ok(map) = serde_yaml::from_str::<HashMap<String, JsonValue>>(&data) {
44        let mut out = HashMap::new();
45        for (uri, val) in map {
46            let bytes = match val {
47                JsonValue::String(s) => s.into_bytes(),
48                other => serde_json::to_vec(&other)
49                    .context("failed to serialize seed value to JSON bytes")?,
50            };
51            out.insert(uri, bytes);
52        }
53        return Ok(out);
54    }
55
56    bail!("failed to parse secrets seed (unsupported format)")
57}
58
59fn seed_entry_to_bytes(entry: SeedEntry) -> Result<(String, Vec<u8>)> {
60    let bytes = if let Some(text) = entry.text {
61        text.into_bytes()
62    } else if let Some(json) = entry.json {
63        serde_json::to_vec(&json).context("failed to serialize seed json value")?
64    } else if let Some(b64) = entry.bytes_b64 {
65        B64_STANDARD
66            .decode(b64.as_bytes())
67            .context("failed to decode seed bytes_b64")?
68    } else if let Some(val) = entry.value {
69        match val {
70            JsonValue::String(s) => s.into_bytes(),
71            other => serde_json::to_vec(&other).context("failed to serialize seed value")?,
72        }
73    } else {
74        bail!("seed entry {} missing value", entry.uri);
75    };
76    Ok((entry.uri, bytes))
77}