app

Local-first trade for farms and co-ops
git clone https://radroots.dev/git/app.git
Log | Files | Refs | README | LICENSE

commit 0e6ca7f3b9f79e3a15377eaf68770c56242b7fad
parent 7603e1ce73b3bd0648e6b4b098adba96e48ae9fc
Author: triesap <triesap@radroots.dev>
Date:   Mon, 19 Jan 2026 17:24:05 +0000

app: add key map validation helpers

- add AppConfigError and AppConfigResult types
- validate required key, param, and object map entries
- expose validation helper from app crate
- add unit test for missing key detection

Diffstat:
Mapp/src/config.rs | 61+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mapp/src/lib.rs | 3+++
2 files changed, 64 insertions(+), 0 deletions(-)

diff --git a/app/src/config.rs b/app/src/config.rs @@ -64,6 +64,55 @@ pub fn app_key_maps_default() -> AppKeyMapConfig { } #[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum AppConfigError { + MissingKeyMap(&'static str), + MissingParamMap(&'static str), + MissingObjMap(&'static str), +} + +pub type AppConfigResult<T> = Result<T, AppConfigError>; + +impl AppConfigError { + pub const fn message(&self) -> &'static str { + match self { + AppConfigError::MissingKeyMap(_) => "error.app.config.key_map_missing", + AppConfigError::MissingParamMap(_) => "error.app.config.param_map_missing", + AppConfigError::MissingObjMap(_) => "error.app.config.obj_map_missing", + } + } +} + +impl std::fmt::Display for AppConfigError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str(self.message()) + } +} + +impl std::error::Error for AppConfigError {} + +pub fn app_key_maps_validate(config: &AppKeyMapConfig) -> AppConfigResult<()> { + if !config.key_map.contains_key("nostr_key") { + return Err(AppConfigError::MissingKeyMap("nostr_key")); + } + if !config.key_map.contains_key("eula_date") { + return Err(AppConfigError::MissingKeyMap("eula_date")); + } + if !config.param_map.contains_key("nostr_profile") { + return Err(AppConfigError::MissingParamMap("nostr_profile")); + } + if !config.param_map.contains_key("radroots_profile") { + return Err(AppConfigError::MissingParamMap("radroots_profile")); + } + if !config.obj_map.contains_key("cfg_data") { + return Err(AppConfigError::MissingObjMap("cfg_data")); + } + if !config.obj_map.contains_key("app_data") { + return Err(AppConfigError::MissingObjMap("app_data")); + } + Ok(()) +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct AppKeystoreConfig { pub nostr_store: RadrootsClientIdbConfig, } @@ -128,7 +177,9 @@ mod tests { app_config_default, app_config_from_env, app_datastore_param_nostr_profile, + app_key_maps_validate, AppConfig, + AppConfigError, AppDatastoreConfig, AppKeyMapConfig, AppKeystoreConfig, @@ -199,4 +250,14 @@ mod tests { ); assert_eq!(app_datastore_param_nostr_profile("abc"), "nostr:abc:profile"); } + + #[test] + fn key_map_validation_requires_expected_keys() { + let config = super::app_key_maps_default(); + assert!(app_key_maps_validate(&config).is_ok()); + let mut missing = AppKeyMapConfig::empty(); + missing.key_map.insert("nostr_key", APP_DATASTORE_KEY_NOSTR_KEY); + let err = app_key_maps_validate(&missing).expect_err("missing keys"); + assert_eq!(err, AppConfigError::MissingKeyMap("eula_date")); + } } diff --git a/app/src/lib.rs b/app/src/lib.rs @@ -14,7 +14,10 @@ pub use config::{ app_datastore_param_nostr_profile, app_datastore_param_radroots_profile, app_key_maps_default, + app_key_maps_validate, AppConfig, + AppConfigError, + AppConfigResult, AppDatastoreConfig, AppDatastoreKeyMap, AppDatastoreKeyObjMap,