v0.3.2-pre.004

This commit is contained in:
2026-08-29 18:42:37 +02:00
parent 0a8fb5dd1b
commit 6d2b1401aa
23 changed files with 958 additions and 57 deletions

View File

@@ -56,11 +56,13 @@
"../../config/composite.ksp-app-wallet-desk.json": "config/composite.ksp-app-wallet-desk.json",
"../../config/std.logging.json": "config/std.logging.json",
"../../config/std.offchain_transport.json": "config/std.offchain_transport.json",
"../../config/std.store.json": "config/std.store.json",
"../../config/std.transport.json": "config/std.transport.json",
"../../config/std.wallet.json": "config/std.wallet.json",
"../../config/schemas/composite.schema.json": "config/schemas/composite.schema.json",
"../../config/schemas/std.logging.schema.json": "config/schemas/std.logging.schema.json",
"../../config/schemas/std.offchain_transport.schema.json": "config/schemas/std.offchain_transport.schema.json",
"../../config/schemas/std.store.schema.json": "config/schemas/std.store.schema.json",
"../../config/schemas/std.transport.schema.json": "config/schemas/std.transport.schema.json",
"../../config/schemas/std.wallet.schema.json": "config/schemas/std.wallet.schema.json"
}

View File

@@ -1,5 +1,5 @@
// file: crates/ksp-app-config-desk/tests/desktop_contract.rs
// version: 10
// version: 11
//! Desktop build/shell contract audits for Config Desk.
@@ -110,7 +110,7 @@ fn pre_018_packaged_runtime_bundles_config_resources_and_activates_shared_writab
let resources = tauri.pointer("/bundle/resources").and_then(serde_json::Value::as_object);
assert!(resources.is_some(), "packaged Config resources map must exist");
if let std::option::Option::Some(resources) = resources {
assert_eq!(resources.len(), 11);
assert_eq!(resources.len(), 13);
assert_eq!(
resources.get("../../config/composite.ksp-app-solprices-desk.json").and_then(serde_json::Value::as_str),
std::option::Option::Some("config/composite.ksp-app-solprices-desk.json"),
@@ -124,6 +124,11 @@ fn pre_018_packaged_runtime_bundles_config_resources_and_activates_shared_writab
resources.get("../../config/schemas/std.offchain_transport.schema.json").and_then(serde_json::Value::as_str),
std::option::Option::Some("config/schemas/std.offchain_transport.schema.json"),
);
assert_eq!(resources.get("../../config/std.store.json").and_then(serde_json::Value::as_str), std::option::Option::Some("config/std.store.json"),);
assert_eq!(
resources.get("../../config/schemas/std.store.schema.json").and_then(serde_json::Value::as_str),
std::option::Option::Some("config/schemas/std.store.schema.json"),
);
assert_eq!(
resources.get("../../config/schemas/std.wallet.schema.json").and_then(serde_json::Value::as_str),
std::option::Option::Some("config/schemas/std.wallet.schema.json"),

View File

@@ -56,11 +56,13 @@
"../../config/composite.ksp-app-wallet-desk.json": "config/composite.ksp-app-wallet-desk.json",
"../../config/std.logging.json": "config/std.logging.json",
"../../config/std.offchain_transport.json": "config/std.offchain_transport.json",
"../../config/std.store.json": "config/std.store.json",
"../../config/std.transport.json": "config/std.transport.json",
"../../config/std.wallet.json": "config/std.wallet.json",
"../../config/schemas/composite.schema.json": "config/schemas/composite.schema.json",
"../../config/schemas/std.logging.schema.json": "config/schemas/std.logging.schema.json",
"../../config/schemas/std.offchain_transport.schema.json": "config/schemas/std.offchain_transport.schema.json",
"../../config/schemas/std.store.schema.json": "config/schemas/std.store.schema.json",
"../../config/schemas/std.transport.schema.json": "config/schemas/std.transport.schema.json",
"../../config/schemas/std.wallet.schema.json": "config/schemas/std.wallet.schema.json"
}

View File

@@ -1,5 +1,5 @@
// file: crates/ksp-app-solprices-desk/tests/desktop_contract.rs
// version: 9
// version: 10
//! Desktop scaffold, shared-template and Config packaging contract audits for SOL Prices Desk `0.2.12`.
@@ -85,19 +85,21 @@ fn pre_002_package_is_mixed_lib_bin_and_frontend_is_scaffold_only() {
}
#[test]
fn pre_003_packaging_contains_current_eleven_config_resources() {
fn pre_004_packaging_contains_current_thirteen_config_resources() {
let root = app_root();
let tauri = read_json(root.join("tauri.conf.json").as_path());
let resources = tauri.pointer("/bundle/resources").and_then(serde_json::Value::as_object);
assert!(resources.is_some());
if let std::option::Option::Some(resources) = resources {
assert_eq!(resources.len(), 11);
assert_eq!(resources.len(), 13);
assert_eq!(
resources.get("../../config/composite.ksp-app-solprices-desk.json").and_then(serde_json::Value::as_str),
std::option::Option::Some("config/composite.ksp-app-solprices-desk.json"),
);
assert!(resources.contains_key("../../config/std.offchain_transport.json"));
assert!(resources.contains_key("../../config/schemas/std.offchain_transport.schema.json"));
assert!(resources.contains_key("../../config/std.store.json"));
assert!(resources.contains_key("../../config/schemas/std.store.schema.json"));
}
let tauri_source = read_text(root.join("src/tauri.rs").as_path());
assert!(tauri_source.contains("ksp_config_lib::prepare_packaged_runtime"));

View File

@@ -56,11 +56,13 @@
"../../config/composite.ksp-app-wallet-desk.json": "config/composite.ksp-app-wallet-desk.json",
"../../config/std.logging.json": "config/std.logging.json",
"../../config/std.offchain_transport.json": "config/std.offchain_transport.json",
"../../config/std.store.json": "config/std.store.json",
"../../config/std.transport.json": "config/std.transport.json",
"../../config/std.wallet.json": "config/std.wallet.json",
"../../config/schemas/composite.schema.json": "config/schemas/composite.schema.json",
"../../config/schemas/std.logging.schema.json": "config/schemas/std.logging.schema.json",
"../../config/schemas/std.offchain_transport.schema.json": "config/schemas/std.offchain_transport.schema.json",
"../../config/schemas/std.store.schema.json": "config/schemas/std.store.schema.json",
"../../config/schemas/std.transport.schema.json": "config/schemas/std.transport.schema.json",
"../../config/schemas/std.wallet.schema.json": "config/schemas/std.wallet.schema.json"
}

View File

@@ -1,5 +1,5 @@
// file: crates/ksp-app-wallet-desk/tests/desktop_contract.rs
// version: 30
// version: 31
//! Desktop build, shell and Config-status contract audits for Wallet Desk.
@@ -432,7 +432,7 @@ fn pre_018_packaged_runtime_bundles_config_resources_and_keeps_wallet_desk_versi
let resources = tauri.pointer("/bundle/resources").and_then(serde_json::Value::as_object);
assert!(resources.is_some(), "packaged Wallet Desk Config resources map must exist");
if let std::option::Option::Some(resources) = resources {
assert_eq!(resources.len(), 11);
assert_eq!(resources.len(), 13);
assert_eq!(
resources.get("../../config/composite.ksp-app-solprices-desk.json").and_then(serde_json::Value::as_str),
std::option::Option::Some("config/composite.ksp-app-solprices-desk.json"),
@@ -449,6 +449,11 @@ fn pre_018_packaged_runtime_bundles_config_resources_and_keeps_wallet_desk_versi
resources.get("../../config/std.offchain_transport.json").and_then(serde_json::Value::as_str),
std::option::Option::Some("config/std.offchain_transport.json"),
);
assert_eq!(resources.get("../../config/std.store.json").and_then(serde_json::Value::as_str), std::option::Option::Some("config/std.store.json"),);
assert_eq!(
resources.get("../../config/schemas/std.store.schema.json").and_then(serde_json::Value::as_str),
std::option::Option::Some("config/schemas/std.store.schema.json"),
);
assert_eq!(
resources.get("../../config/schemas/std.offchain_transport.schema.json").and_then(serde_json::Value::as_str),
std::option::Option::Some("config/schemas/std.offchain_transport.schema.json"),

View File

@@ -1,5 +1,5 @@
// file: crates/ksp-app-wallet-desk/tests/release_compliance.rs
// version: 9
// version: 10
//! Release-wide deterministic compliance canaries for Wallet Desk.
@@ -199,7 +199,7 @@ fn packaged_resources_include_only_registered_config_sources_and_schemas() {
std::option::Option::Some(value) => value,
std::option::Option::None => return,
};
assert_eq!(resources.len(), 11);
assert_eq!(resources.len(), 13);
for (source, destination) in resources {
let destination = destination.as_str();
assert!(destination.is_some(), "resource destination must be textual");

View File

@@ -1,5 +1,5 @@
# file: crates/ksp-config-lib/Cargo.toml
# version: 9
# version: 10
[package]
name = "ksp-config-lib"
@@ -14,6 +14,7 @@ ksp-core-lib = { path = "../ksp-core-lib" }
ksp-logging-lib = { path = "../ksp-logging-lib" }
ksp-offchain-transport-lib = { path = "../ksp-offchain-transport-lib" }
ksp-onchain-transport-lib = { path = "../ksp-onchain-transport-lib" }
ksp-store-lib = { path = "../ksp-store-lib", default-features = false }
serde = { workspace = true, features = ["derive"] }
serde_json.workspace = true

View File

@@ -1,5 +1,5 @@
// file: crates/ksp-config-lib/src/lib.rs
// version: 20
// version: 21
#![warn(missing_docs)]
#![deny(unreachable_pub)]
@@ -9,7 +9,7 @@
//!
//! The `0.1.3` surface owns bootstrap roots, the logical file registry, JSON/JSON Schema validation, standard-document profiles, generic composites and
//! KSP/KSPB environment resolution through process + `.env` + fallback precedence. Resolved values preserve real/safe representations, sensitivity and
//! provenance. Standard Logging, on-chain Transport (HTTP/WebSocket/Yellowstone gRPC) and Wallet documents map explicitly to their runtime consumer
//! provenance. Standard Logging, on-chain Transport (HTTP/WebSocket/Yellowstone gRPC), Store and Wallet documents map explicitly to their runtime consumer
//! contracts, while the management surface provides typed Logging mutation, safe environment reports, explicit privileged reveal calls and atomic
//! JSON/`.env` persistence.
@@ -27,6 +27,7 @@ mod persistence;
mod profile;
mod registry;
mod sensitivity;
mod store;
mod transport;
mod wallet;
@@ -164,6 +165,10 @@ pub use self::registry::DEFAULT_STD_LOGGING_SCHEMA_FILENAME;
pub use self::registry::DEFAULT_STD_OFFCHAIN_TRANSPORT_FILENAME;
/// Default physical filename for the standard Off-chain Transport JSON Schema document.
pub use self::registry::DEFAULT_STD_OFFCHAIN_TRANSPORT_SCHEMA_FILENAME;
/// Default physical filename for the standard Store configuration document.
pub use self::registry::DEFAULT_STD_STORE_FILENAME;
/// Default physical filename for the standard Store JSON Schema document.
pub use self::registry::DEFAULT_STD_STORE_SCHEMA_FILENAME;
/// Default physical filename for the standard HTTP + WebSocket + Yellowstone gRPC Transport configuration document.
pub use self::registry::DEFAULT_STD_TRANSPORT_FILENAME;
/// Default physical filename for the standard HTTP + WebSocket + Yellowstone gRPC Transport JSON Schema document.
@@ -182,6 +187,8 @@ pub use self::registry::FILE_ID_SCHEMA_COMPOSITE;
pub use self::registry::FILE_ID_SCHEMA_STD_LOGGING;
/// Logical file identifier for the standard Off-chain Transport JSON Schema document.
pub use self::registry::FILE_ID_SCHEMA_STD_OFFCHAIN_TRANSPORT;
/// Logical file identifier for the standard Store JSON Schema document.
pub use self::registry::FILE_ID_SCHEMA_STD_STORE;
/// Logical file identifier for the standard HTTP + WebSocket + Yellowstone gRPC Transport JSON Schema document.
pub use self::registry::FILE_ID_SCHEMA_STD_TRANSPORT;
/// Logical file identifier for the standard Wallet JSON Schema document.
@@ -190,6 +197,8 @@ pub use self::registry::FILE_ID_SCHEMA_STD_WALLET;
pub use self::registry::FILE_ID_STD_LOGGING;
/// Logical file identifier for the standard Off-chain Transport configuration document.
pub use self::registry::FILE_ID_STD_OFFCHAIN_TRANSPORT;
/// Logical file identifier for the standard Store configuration document.
pub use self::registry::FILE_ID_STD_STORE;
/// Logical file identifier for the standard HTTP + WebSocket + Yellowstone gRPC Transport configuration document.
pub use self::registry::FILE_ID_STD_TRANSPORT;
/// Logical file identifier for the standard Wallet configuration document.
@@ -204,6 +213,8 @@ pub use self::sensitivity::REDACTED_CONFIG_VALUE;
pub use self::sensitivity::ResolvedConfigJson;
/// One resolved Config string preserving real/safe representations and provenance.
pub use self::sensitivity::ResolvedConfigText;
/// Effective standard Store configuration mapped to backend-neutral Store settings.
pub use self::store::ResolvedStoreConfig;
/// Effective standard Transport configuration mapped to HTTP plus optional WebSocket and Yellowstone gRPC runtime settings.
pub use self::transport::ResolvedTransportConfig;
/// Effective standard Wallet configuration resolved to validated filesystem roots.

View File

@@ -1,5 +1,5 @@
// file: crates/ksp-config-lib/src/registry.rs
// version: 12
// version: 13
/// Bootstrap argument used to replace a known Config filename mapping.
pub const ARG_FILE_MAP: &str = "--filemap";
@@ -17,6 +17,10 @@ pub const DEFAULT_STD_LOGGING_SCHEMA_FILENAME: &str = "std.logging.schema.json";
pub const DEFAULT_STD_OFFCHAIN_TRANSPORT_FILENAME: &str = "std.offchain_transport.json";
/// Default physical filename for the standard Off-chain Transport JSON Schema document.
pub const DEFAULT_STD_OFFCHAIN_TRANSPORT_SCHEMA_FILENAME: &str = "std.offchain_transport.schema.json";
/// Default physical filename for the standard Store configuration document.
pub const DEFAULT_STD_STORE_FILENAME: &str = "std.store.json";
/// Default physical filename for the standard Store JSON Schema document.
pub const DEFAULT_STD_STORE_SCHEMA_FILENAME: &str = "std.store.schema.json";
/// Default physical filename for the standard HTTP + WebSocket + Yellowstone gRPC Transport configuration document.
pub const DEFAULT_STD_TRANSPORT_FILENAME: &str = "std.transport.json";
/// Default physical filename for the standard HTTP + WebSocket + Yellowstone gRPC Transport JSON Schema document.
@@ -35,6 +39,8 @@ pub const FILE_ID_SCHEMA_COMPOSITE: &str = "schema.composite";
pub const FILE_ID_SCHEMA_STD_LOGGING: &str = "schema.std.logging";
/// Logical file identifier for the standard Off-chain Transport JSON Schema document.
pub const FILE_ID_SCHEMA_STD_OFFCHAIN_TRANSPORT: &str = "schema.std.offchain_transport";
/// Logical file identifier for the standard Store JSON Schema document.
pub const FILE_ID_SCHEMA_STD_STORE: &str = "schema.std.store";
/// Logical file identifier for the standard HTTP + WebSocket + Yellowstone gRPC Transport JSON Schema document.
pub const FILE_ID_SCHEMA_STD_TRANSPORT: &str = "schema.std.transport";
/// Logical file identifier for the standard Wallet JSON Schema document.
@@ -43,6 +49,8 @@ pub const FILE_ID_SCHEMA_STD_WALLET: &str = "schema.std.wallet";
pub const FILE_ID_STD_LOGGING: &str = "cfg.std.logging";
/// Logical file identifier for the standard Off-chain Transport configuration document.
pub const FILE_ID_STD_OFFCHAIN_TRANSPORT: &str = "cfg.std.offchain_transport";
/// Logical file identifier for the standard Store configuration document.
pub const FILE_ID_STD_STORE: &str = "cfg.std.store";
/// Logical file identifier for the standard HTTP + WebSocket + Yellowstone gRPC Transport configuration document.
pub const FILE_ID_STD_TRANSPORT: &str = "cfg.std.transport";
/// Logical file identifier for the standard Wallet configuration document.
@@ -214,6 +222,22 @@ impl ConfigFileRegistry {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let store = ConfigFileDescriptor::new(
FILE_ID_STD_STORE,
ConfigFileKind::Config,
DEFAULT_STD_STORE_FILENAME,
std::option::Option::Some(FILE_ID_SCHEMA_STD_STORE),
);
let store = match store {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let store_schema =
ConfigFileDescriptor::new(FILE_ID_SCHEMA_STD_STORE, ConfigFileKind::Schema, DEFAULT_STD_STORE_SCHEMA_FILENAME, std::option::Option::None);
let store_schema = match store_schema {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let transport = ConfigFileDescriptor::new(
FILE_ID_STD_TRANSPORT,
ConfigFileKind::Config,
@@ -254,6 +278,8 @@ impl ConfigFileRegistry {
logging_schema,
offchain_transport,
offchain_transport_schema,
store,
store_schema,
transport,
transport_schema,
wallet,

View File

@@ -0,0 +1,264 @@
// file: crates/ksp-config-lib/src/store.rs
// version: 1
/// Effective standard Store configuration mapped to `ksp_store_lib::StoreSettings`.
pub struct ResolvedStoreConfig {
effective: crate::ResolvedConfigJson,
file_id: crate::ConfigFileId,
profile_id: String,
selection_source: crate::ConfigProfileSelectionSource,
settings: ksp_store_lib::StoreSettings,
source_path: std::path::PathBuf,
}
impl ResolvedStoreConfig {
/// Returns the detailed environment-resolved Config view.
#[must_use]
pub const fn effective(&self) -> &crate::ResolvedConfigJson {
return &self.effective;
}
/// Returns the logical Config file identifier used by this runtime configuration.
#[must_use]
pub const fn file_id(&self) -> &crate::ConfigFileId {
return &self.file_id;
}
/// Returns the selected standard Store profile identifier.
#[must_use]
pub fn profile_id(&self) -> &str {
return self.profile_id.as_str();
}
/// Returns the source that selected the standard Store profile.
#[must_use]
pub const fn selection_source(&self) -> crate::ConfigProfileSelectionSource {
return self.selection_source;
}
/// Borrows the backend-neutral Store settings without exposing the connection URI.
#[must_use]
pub const fn settings(&self) -> &ksp_store_lib::StoreSettings {
return &self.settings;
}
/// Consumes the resolved Config and returns the Store-owned runtime settings.
#[must_use]
pub fn into_settings(self) -> ksp_store_lib::StoreSettings {
return self.settings;
}
/// Returns the physical source Config document path.
#[must_use]
pub fn source_path(&self) -> &std::path::Path {
return self.source_path.as_path();
}
}
impl std::fmt::Debug for ResolvedStoreConfig {
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
return formatter
.debug_struct("ResolvedStoreConfig")
.field("effective", &self.effective)
.field("file_id", &self.file_id)
.field("profile_id", &self.profile_id)
.field("selection_source", &self.selection_source)
.field("settings", &self.settings)
.field("source_path", &self.source_path)
.finish();
}
}
impl crate::ConfigDocumentEngine {
/// Loads `std.store`, resolves one profile/environment and maps it to backend-neutral Store settings.
pub fn load_resolved_store_config(
&self,
requested_profile: std::option::Option<&str>,
environment: &crate::ConfigEnvironment,
) -> ksp_core_lib::Result<ResolvedStoreConfig> {
let file_id = crate::ConfigFileId::new(crate::FILE_ID_STD_STORE);
let file_id = match file_id {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let profile = self.load_resolved_profile(&file_id, requested_profile);
let profile = match profile {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
return resolve_store_profile(&profile, environment);
}
/// Maps an already resolved `cfg.std.store` profile while preserving its selection provenance.
pub fn resolve_store_config_profile(
&self,
profile: &crate::ResolvedConfigProfile,
environment: &crate::ConfigEnvironment,
) -> ksp_core_lib::Result<ResolvedStoreConfig> {
if profile.file_id().as_str() != crate::FILE_ID_STD_STORE {
return std::result::Result::Err(effective_error(profile, "resolved Config profile does not reference the standard Store document"));
}
let descriptor = self.registry().descriptor(profile.file_id());
if let std::result::Result::Err(error) = descriptor {
return std::result::Result::Err(error);
}
return resolve_store_profile(profile, environment);
}
}
#[derive(serde::Deserialize)]
#[serde(deny_unknown_fields)]
struct EffectiveStoreSource {
backend: String,
format_version: u32,
postgres: EffectivePostgresSource,
profile_id: String,
}
#[derive(serde::Deserialize)]
#[serde(deny_unknown_fields)]
struct EffectivePostgresSource {
bootstrap: EffectivePostgresBootstrapSource,
connection_uri: String,
pool: EffectivePostgresPoolSource,
shutdown_timeout_ms: u64,
tls: EffectivePostgresTlsSource,
}
#[derive(serde::Deserialize)]
#[serde(deny_unknown_fields)]
struct EffectivePostgresPoolSource {
connect_timeout_ms: u64,
create_timeout_ms: u64,
max_connections: u32,
recycle_timeout_ms: u64,
wait_timeout_ms: u64,
}
#[derive(serde::Deserialize)]
#[serde(deny_unknown_fields)]
struct EffectivePostgresTlsSource {
mode: String,
}
#[derive(serde::Deserialize)]
#[serde(deny_unknown_fields)]
struct EffectivePostgresBootstrapSource {
auto_migrate: bool,
migration_lock_timeout_ms: u64,
migration_timeout_ms: u64,
}
fn resolve_store_profile(profile: &crate::ResolvedConfigProfile, environment: &crate::ConfigEnvironment) -> ksp_core_lib::Result<ResolvedStoreConfig> {
ksp_logging_lib::trace!(target: crate::TRACING_TARGET, profile_id = profile.profile_id(), "mapping standard Store Config profile");
let effective = profile.resolve_effective_environment_detailed(environment);
let effective = match effective {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let provenance = validate_connection_uri_provenance(&effective, profile);
if let std::result::Result::Err(error) = provenance {
return std::result::Result::Err(error);
}
let source = serde_json::from_value::<EffectiveStoreSource>(effective.value().clone());
let source = match source {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => {
return std::result::Result::Err(
effective_error(profile, "effective Store Config cannot be decoded into the runtime adapter contract").with_source(error),
);
},
};
if source.format_version != 1 {
return std::result::Result::Err(effective_error(profile, "effective Store format_version is unsupported"));
}
if source.profile_id != profile.profile_id() {
return std::result::Result::Err(effective_error(profile, "effective Store profile_id does not match the selected profile"));
}
if source.backend != "postgres" {
return std::result::Result::Err(effective_error(profile, "effective Store backend is unsupported").with_context("backend", source.backend));
}
let tls_mode = match source.postgres.tls.mode.as_str() {
"disabled" => ksp_store_lib::PostgresTlsMode::Disabled,
"verify_full" => ksp_store_lib::PostgresTlsMode::VerifyFull,
_ => return std::result::Result::Err(effective_error(profile, "effective Store PostgreSQL TLS mode is unsupported")),
};
let pool = ksp_store_lib::PostgresPoolSettings::new(
source.postgres.pool.max_connections,
std::time::Duration::from_millis(source.postgres.pool.connect_timeout_ms),
std::time::Duration::from_millis(source.postgres.pool.wait_timeout_ms),
std::time::Duration::from_millis(source.postgres.pool.create_timeout_ms),
std::time::Duration::from_millis(source.postgres.pool.recycle_timeout_ms),
);
let bootstrap = ksp_store_lib::PostgresBootstrapSettings::new(
source.postgres.bootstrap.auto_migrate,
std::time::Duration::from_millis(source.postgres.bootstrap.migration_timeout_ms),
std::time::Duration::from_millis(source.postgres.bootstrap.migration_lock_timeout_ms),
);
let postgres = ksp_store_lib::PostgresStoreSettings::new(source.postgres.connection_uri, pool, tls_mode, bootstrap);
let settings = ksp_store_lib::StoreSettings::new(
ksp_store_lib::StoreBackendSettings::Postgres(postgres),
std::time::Duration::from_millis(source.postgres.shutdown_timeout_ms),
);
if let std::result::Result::Err(error) = settings.validate() {
return std::result::Result::Err(store_contract_error(profile, &error));
}
ksp_logging_lib::debug!(
target: crate::TRACING_TARGET,
profile_id = profile.profile_id(),
backend = settings.backend_kind().code(),
"mapped standard Store Config to Store settings"
);
return std::result::Result::Ok(ResolvedStoreConfig {
effective,
file_id: profile.file_id().clone(),
profile_id: profile.profile_id().to_owned(),
selection_source: profile.selection_source(),
settings,
source_path: profile.path().to_path_buf(),
});
}
fn validate_connection_uri_provenance(effective: &crate::ResolvedConfigJson, profile: &crate::ResolvedConfigProfile) -> ksp_core_lib::Result<()> {
let provenance = match effective.provenance_at("/postgres/connection_uri") {
std::option::Option::Some(value) => value,
std::option::Option::None => return std::result::Result::Err(effective_error(profile, "Store PostgreSQL connection URI provenance is unavailable")),
};
let mut has_secret_environment = false;
for item in provenance {
let variable_name = match item.variable_name() {
std::option::Option::Some(value) => value,
std::option::Option::None => continue,
};
let sensitivity = crate::ConfigSensitivity::from_variable_name(variable_name);
let sensitivity = match sensitivity {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
if !sensitivity.is_secret() {
return std::result::Result::Err(effective_error(profile, "Store PostgreSQL connection URI may reference only secret environment variables"));
}
has_secret_environment = true;
}
if !has_secret_environment {
return std::result::Result::Err(effective_error(profile, "Store PostgreSQL connection URI requires secret environment provenance"));
}
return std::result::Result::Ok(());
}
fn store_contract_error(profile: &crate::ResolvedConfigProfile, error: &ksp_core_lib::Error) -> ksp_core_lib::Error {
return effective_error(profile, "effective Store settings fail the Store runtime contract")
.with_context("store_error_domain", error.code().domain())
.with_context("store_error_code", error.code().code());
}
fn effective_error(profile: &crate::ResolvedConfigProfile, reason: &'static str) -> ksp_core_lib::Error {
return ksp_core_lib::Error::new(crate::ERROR_CODE_EFFECTIVE_CONFIG_INVALID, "effective Config cannot be mapped to the requested runtime contract")
.with_context("file_id", profile.file_id().as_str())
.with_context("profile_id", profile.profile_id())
.with_context("reason", reason);
}
#[cfg(test)]
#[path = "../unit_tests/store.rs"]
mod tests;

View File

@@ -1,5 +1,5 @@
// file: crates/ksp-config-lib/tests/ownership.rs
// version: 8
// version: 9
//! Workspace ownership audits for KSP application configuration boundaries.
@@ -280,6 +280,49 @@ fn workspace_crates_do_not_hardcode_config_managed_physical_files() {
}
}
#[test]
fn store_config_adapter_does_not_force_backend_feature_or_reverse_dependency() {
let root = workspace_root();
let config_manifest_path = root.join("crates/ksp-config-lib/Cargo.toml");
let config_manifest = std::fs::read_to_string(config_manifest_path.as_path());
assert!(config_manifest.is_ok(), "unable to read {}", config_manifest_path.display());
if let std::result::Result::Ok(config_manifest) = config_manifest {
assert!(
config_manifest.contains("ksp-store-lib = { path = \"../ksp-store-lib\", default-features = false }"),
"Config -> Store dependency must not force a physical backend feature"
);
}
for crate_name in ["ksp-store-lib", "ksp-store-postgres-lib"] {
let manifest_path = root.join("crates").join(crate_name).join("Cargo.toml");
let manifest = std::fs::read_to_string(manifest_path.as_path());
assert!(manifest.is_ok(), "unable to read {}", manifest_path.display());
if let std::result::Result::Ok(manifest) = manifest {
assert!(!manifest.contains("ksp-config-lib"), "{} must not depend back on Config", manifest_path.display());
}
}
}
#[test]
fn store_runtime_sources_do_not_bypass_config_for_environment_or_libpq_files() {
let root = workspace_root();
for crate_name in ["ksp-store-lib", "ksp-store-postgres-lib"] {
let source_root = root.join("crates").join(crate_name).join("src");
let mut rust_files = std::vec::Vec::new();
collect_rust_files(source_root.as_path(), &mut rust_files);
for rust_file in rust_files {
let source = std::fs::read_to_string(rust_file.as_path());
assert!(source.is_ok(), "unable to read {}", rust_file.display());
let source = match source {
std::result::Result::Ok(value) => non_comment_source(value.as_str()),
std::result::Result::Err(_) => continue,
};
for forbidden in ["std::env", "dotenv", "KSP_", "KSPB_", "\"PG", ".pgpass"] {
assert!(!source.contains(forbidden), "{} bypasses Config through forbidden Store environment/libpq token {forbidden}", rust_file.display());
}
}
}
}
#[test]
fn environment_name_scanner_ignores_namespace_labels_but_keeps_concrete_names() {
let source = r#"

View File

@@ -1,8 +1,8 @@
// file: crates/ksp-config-lib/tests/public_api.rs
// version: 25
// version: 26
//! Integration tests for the public `ksp-config-lib` bootstrap, registry, JSON/profile/composite, environment-resolution, sensitivity,
//! Logging/Transport adapters and management contracts.
//! Logging/Transport/Store adapters and management contracts.
#[test]
fn bootstrap_contract_is_available_from_crate_root() {
@@ -80,19 +80,21 @@ fn registry_descriptor_inventory_is_available_from_crate_root() {
assert!(registry.is_ok(), "public registry should remain constructible: {registry:?}");
if let std::result::Result::Ok(registry) = registry {
let descriptors: std::vec::Vec<&ksp_config_lib::ConfigFileDescriptor> = registry.descriptors().collect();
assert_eq!(descriptors.len(), 11);
assert_eq!(descriptors.len(), 13);
assert_eq!(descriptors[0].file_id().as_str(), ksp_config_lib::FILE_ID_COMPOSITE_KSP_APP_SOLPRICES_DESK);
assert_eq!(descriptors[1].file_id().as_str(), ksp_config_lib::FILE_ID_COMPOSITE_KSP_APP_WALLET_DESK);
assert_eq!(descriptors[2].file_id().as_str(), ksp_config_lib::FILE_ID_STD_LOGGING);
assert_eq!(descriptors[3].file_id().as_str(), ksp_config_lib::FILE_ID_STD_OFFCHAIN_TRANSPORT);
assert_eq!(descriptors[4].file_id().as_str(), ksp_config_lib::FILE_ID_STD_TRANSPORT);
assert_eq!(descriptors[5].file_id().as_str(), ksp_config_lib::FILE_ID_STD_WALLET);
assert_eq!(descriptors[6].file_id().as_str(), ksp_config_lib::FILE_ID_SCHEMA_COMPOSITE);
assert_eq!(descriptors[7].file_id().as_str(), ksp_config_lib::FILE_ID_SCHEMA_STD_LOGGING);
assert_eq!(descriptors[8].file_id().as_str(), ksp_config_lib::FILE_ID_SCHEMA_STD_OFFCHAIN_TRANSPORT);
assert_eq!(descriptors[9].file_id().as_str(), ksp_config_lib::FILE_ID_SCHEMA_STD_TRANSPORT);
assert_eq!(descriptors[10].file_id().as_str(), ksp_config_lib::FILE_ID_SCHEMA_STD_WALLET);
let schema_file_id = descriptors[5].schema_file_id();
assert_eq!(descriptors[4].file_id().as_str(), ksp_config_lib::FILE_ID_STD_STORE);
assert_eq!(descriptors[5].file_id().as_str(), ksp_config_lib::FILE_ID_STD_TRANSPORT);
assert_eq!(descriptors[6].file_id().as_str(), ksp_config_lib::FILE_ID_STD_WALLET);
assert_eq!(descriptors[7].file_id().as_str(), ksp_config_lib::FILE_ID_SCHEMA_COMPOSITE);
assert_eq!(descriptors[8].file_id().as_str(), ksp_config_lib::FILE_ID_SCHEMA_STD_LOGGING);
assert_eq!(descriptors[9].file_id().as_str(), ksp_config_lib::FILE_ID_SCHEMA_STD_OFFCHAIN_TRANSPORT);
assert_eq!(descriptors[10].file_id().as_str(), ksp_config_lib::FILE_ID_SCHEMA_STD_STORE);
assert_eq!(descriptors[11].file_id().as_str(), ksp_config_lib::FILE_ID_SCHEMA_STD_TRANSPORT);
assert_eq!(descriptors[12].file_id().as_str(), ksp_config_lib::FILE_ID_SCHEMA_STD_WALLET);
let schema_file_id = descriptors[6].schema_file_id();
assert!(schema_file_id.is_some(), "public Wallet descriptor should preserve schema association");
if let std::option::Option::Some(schema_file_id) = schema_file_id {
assert_eq!(schema_file_id.as_str(), ksp_config_lib::FILE_ID_SCHEMA_STD_WALLET);
@@ -211,6 +213,18 @@ fn logging_adapter_contract_is_available_from_crate_root() {
assert!(std::mem::size_of::<ksp_config_lib::ResolvedLoggingConfig>() > 0);
}
#[test]
fn store_adapter_contract_is_available_from_crate_root() {
let adapter = ksp_config_lib::ConfigDocumentEngine::load_resolved_store_config;
let composite_adapter = ksp_config_lib::ConfigDocumentEngine::resolve_store_config_profile;
let _ = (adapter, composite_adapter);
assert_eq!(ksp_config_lib::FILE_ID_STD_STORE, "cfg.std.store");
assert_eq!(ksp_config_lib::FILE_ID_SCHEMA_STD_STORE, "schema.std.store");
assert_eq!(ksp_config_lib::DEFAULT_STD_STORE_FILENAME, "std.store.json");
assert_eq!(ksp_config_lib::DEFAULT_STD_STORE_SCHEMA_FILENAME, "std.store.schema.json");
assert!(std::mem::size_of::<ksp_config_lib::ResolvedStoreConfig>() > 0);
}
#[test]
fn management_contracts_are_available_from_crate_root() {
let workspace = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../..");

View File

@@ -1,5 +1,5 @@
// file: crates/ksp-config-lib/unit_tests/registry.rs
// version: 10
// version: 11
#[test]
fn descriptors_expose_complete_registry_in_deterministic_file_id_order() {
@@ -7,7 +7,7 @@ fn descriptors_expose_complete_registry_in_deterministic_file_id_order() {
assert!(registry.is_ok(), "default registry should be valid: {registry:?}");
if let std::result::Result::Ok(registry) = registry {
let descriptors: std::vec::Vec<&crate::ConfigFileDescriptor> = registry.descriptors().collect();
assert_eq!(descriptors.len(), 11);
assert_eq!(descriptors.len(), 13);
assert_eq!(descriptors[0].file_id().as_str(), crate::FILE_ID_COMPOSITE_KSP_APP_SOLPRICES_DESK);
assert_eq!(descriptors[0].filename(), std::path::Path::new(crate::DEFAULT_COMPOSITE_KSP_APP_SOLPRICES_DESK_FILENAME));
assert_eq!(descriptors[0].schema_file_id().map(crate::ConfigFileId::as_str), std::option::Option::Some(crate::FILE_ID_SCHEMA_COMPOSITE));
@@ -15,17 +15,19 @@ fn descriptors_expose_complete_registry_in_deterministic_file_id_order() {
assert_eq!(descriptors[1].filename(), std::path::Path::new(crate::DEFAULT_COMPOSITE_KSP_APP_WALLET_DESK_FILENAME));
assert_eq!(descriptors[2].file_id().as_str(), crate::FILE_ID_STD_LOGGING);
assert_eq!(descriptors[3].file_id().as_str(), crate::FILE_ID_STD_OFFCHAIN_TRANSPORT);
assert_eq!(descriptors[4].file_id().as_str(), crate::FILE_ID_STD_TRANSPORT);
assert_eq!(descriptors[5].file_id().as_str(), crate::FILE_ID_STD_WALLET);
assert_eq!(descriptors[5].filename(), std::path::Path::new(crate::DEFAULT_STD_WALLET_FILENAME));
assert_eq!(descriptors[5].schema_file_id().map(crate::ConfigFileId::as_str), std::option::Option::Some(crate::FILE_ID_SCHEMA_STD_WALLET));
assert_eq!(descriptors[6].file_id().as_str(), crate::FILE_ID_SCHEMA_COMPOSITE);
assert_eq!(descriptors[7].file_id().as_str(), crate::FILE_ID_SCHEMA_STD_LOGGING);
assert_eq!(descriptors[8].file_id().as_str(), crate::FILE_ID_SCHEMA_STD_OFFCHAIN_TRANSPORT);
assert_eq!(descriptors[9].file_id().as_str(), crate::FILE_ID_SCHEMA_STD_TRANSPORT);
assert_eq!(descriptors[10].file_id().as_str(), crate::FILE_ID_SCHEMA_STD_WALLET);
assert!(descriptors[0..6].iter().all(|descriptor| return descriptor.kind() == crate::ConfigFileKind::Config));
assert!(descriptors[6..11].iter().all(|descriptor| return descriptor.kind() == crate::ConfigFileKind::Schema));
assert_eq!(descriptors[4].file_id().as_str(), crate::FILE_ID_STD_STORE);
assert_eq!(descriptors[5].file_id().as_str(), crate::FILE_ID_STD_TRANSPORT);
assert_eq!(descriptors[6].file_id().as_str(), crate::FILE_ID_STD_WALLET);
assert_eq!(descriptors[6].filename(), std::path::Path::new(crate::DEFAULT_STD_WALLET_FILENAME));
assert_eq!(descriptors[6].schema_file_id().map(crate::ConfigFileId::as_str), std::option::Option::Some(crate::FILE_ID_SCHEMA_STD_WALLET));
assert_eq!(descriptors[7].file_id().as_str(), crate::FILE_ID_SCHEMA_COMPOSITE);
assert_eq!(descriptors[8].file_id().as_str(), crate::FILE_ID_SCHEMA_STD_LOGGING);
assert_eq!(descriptors[9].file_id().as_str(), crate::FILE_ID_SCHEMA_STD_OFFCHAIN_TRANSPORT);
assert_eq!(descriptors[10].file_id().as_str(), crate::FILE_ID_SCHEMA_STD_STORE);
assert_eq!(descriptors[11].file_id().as_str(), crate::FILE_ID_SCHEMA_STD_TRANSPORT);
assert_eq!(descriptors[12].file_id().as_str(), crate::FILE_ID_SCHEMA_STD_WALLET);
assert!(descriptors[0..7].iter().all(|descriptor| return descriptor.kind() == crate::ConfigFileKind::Config));
assert!(descriptors[7..13].iter().all(|descriptor| return descriptor.kind() == crate::ConfigFileKind::Schema));
}
}
@@ -114,6 +116,27 @@ fn defaults_register_offchain_transport_document_and_schema_with_distinct_roots(
}
}
#[test]
fn defaults_register_store_document_and_schema_with_distinct_roots() {
let registry = crate::ConfigFileRegistry::defaults();
assert!(registry.is_ok());
if let std::result::Result::Ok(registry) = registry {
let config_id = crate::ConfigFileId::new(crate::FILE_ID_STD_STORE);
let schema_id = crate::ConfigFileId::new(crate::FILE_ID_SCHEMA_STD_STORE);
if let (std::result::Result::Ok(config_id), std::result::Result::Ok(schema_id)) = (config_id, schema_id) {
let config = registry.descriptor(&config_id);
let schema = registry.descriptor(&schema_id);
if let (std::result::Result::Ok(config), std::result::Result::Ok(schema)) = (config, schema) {
assert_eq!(config.kind(), crate::ConfigFileKind::Config);
assert_eq!(config.filename(), std::path::Path::new(crate::DEFAULT_STD_STORE_FILENAME));
assert_eq!(config.schema_file_id(), std::option::Option::Some(&schema_id));
assert_eq!(schema.kind(), crate::ConfigFileKind::Schema);
assert_eq!(schema.filename(), std::path::Path::new(crate::DEFAULT_STD_STORE_SCHEMA_FILENAME));
}
}
}
}
#[test]
fn defaults_register_transport_document_and_schema_with_distinct_roots() {
let registry = crate::ConfigFileRegistry::defaults();

View File

@@ -0,0 +1,163 @@
// file: crates/ksp-config-lib/unit_tests/store.rs
// version: 1
#[test]
fn committed_store_profile_maps_exact_runtime_settings_and_secret_fallback() {
let engine = committed_engine();
let engine = match engine {
std::result::Result::Ok(value) => value,
std::result::Result::Err(_) => return,
};
let environment = crate::ConfigEnvironment::from_maps(std::collections::BTreeMap::new(), std::collections::BTreeMap::new());
let resolved = engine.load_resolved_store_config(std::option::Option::None, &environment);
assert!(resolved.is_ok(), "committed Store profile should map without opening PostgreSQL: {resolved:?}");
if let std::result::Result::Ok(resolved) = resolved {
assert_eq!(resolved.file_id().as_str(), crate::FILE_ID_STD_STORE);
assert_eq!(resolved.profile_id(), "postgres_default");
assert_eq!(resolved.selection_source(), crate::ConfigProfileSelectionSource::DefaultProfile);
assert_eq!(resolved.settings().backend_kind(), ksp_store_lib::StoreBackendKind::Postgres);
assert_eq!(resolved.settings().shutdown_timeout(), std::time::Duration::from_millis(5_000));
let postgres = match resolved.settings().backend() {
ksp_store_lib::StoreBackendSettings::Postgres(postgres) => std::option::Option::Some(postgres),
_ => std::option::Option::None,
};
assert!(postgres.is_some(), "pre.004 fixture should map to the PostgreSQL Store backend");
if let std::option::Option::Some(postgres) = postgres {
assert_eq!(postgres.pool().max_connections(), 8);
assert_eq!(postgres.pool().connect_timeout(), std::time::Duration::from_millis(10_000));
assert_eq!(postgres.pool().wait_timeout(), std::time::Duration::from_millis(5_000));
assert_eq!(postgres.pool().create_timeout(), std::time::Duration::from_millis(10_000));
assert_eq!(postgres.pool().recycle_timeout(), std::time::Duration::from_millis(5_000));
assert_eq!(postgres.tls_mode(), ksp_store_lib::PostgresTlsMode::VerifyFull);
assert!(postgres.bootstrap().auto_migrate());
assert_eq!(postgres.bootstrap().migration_timeout(), std::time::Duration::from_millis(30_000));
assert_eq!(postgres.bootstrap().migration_lock_timeout(), std::time::Duration::from_millis(10_000));
}
assert!(resolved.effective().sensitivity().is_secret());
let safe = resolved.effective().safe_value().to_string();
assert!(!safe.contains("postgresql://localhost/ksp"));
assert!(safe.contains(crate::REDACTED_CONFIG_VALUE));
let debug = format!("{resolved:?}");
assert!(!debug.contains("postgresql://localhost/ksp"));
}
}
#[test]
fn process_store_uri_wins_and_remains_redacted_in_safe_views() {
let engine = committed_engine();
let engine = match engine {
std::result::Result::Ok(value) => value,
std::result::Result::Err(_) => return,
};
let canary = "postgresql://secret-user:secret-pass@db.example/ksp";
let mut process = std::collections::BTreeMap::<String, String>::new();
process.insert("KSP_SECRET_STORE_POSTGRES_URI".to_owned(), canary.to_owned());
let environment = crate::ConfigEnvironment::from_maps(process, std::collections::BTreeMap::new());
let resolved = engine.load_resolved_store_config(std::option::Option::None, &environment);
assert!(resolved.is_ok(), "secret process Store URI should map: {resolved:?}");
if let std::result::Result::Ok(resolved) = resolved {
assert_eq!(resolved.effective().value().pointer("/postgres/connection_uri").and_then(serde_json::Value::as_str), std::option::Option::Some(canary));
assert!(!resolved.effective().safe_value().to_string().contains(canary));
assert!(!format!("{resolved:?}").contains(canary));
let provenance = resolved.effective().provenance_at("/postgres/connection_uri");
assert!(provenance.is_some());
if let std::option::Option::Some(provenance) = provenance {
assert!(provenance.iter().any(|item| return item.environment_source() == std::option::Option::Some(crate::ConfigEnvironmentSource::Process)));
}
}
}
#[test]
fn literal_or_nonsecret_store_uri_is_rejected_by_effective_adapter() {
for value in ["postgresql://literal.invalid/ksp", "${KSP_PUBLIC_STORE_POSTGRES_URI:-postgresql://public.invalid/ksp}"] {
let fixture = tempfile::tempdir();
assert!(fixture.is_ok());
let fixture = match fixture {
std::result::Result::Ok(value) => value,
std::result::Result::Err(_) => return,
};
let source = committed_document_value();
let mut source = match source {
std::result::Result::Ok(value) => value,
std::result::Result::Err(_) => return,
};
let profiles = source.get_mut("profiles").and_then(serde_json::Value::as_array_mut);
if let std::option::Option::Some(profiles) = profiles {
if let std::option::Option::Some(profile) = profiles.first_mut() {
profile["postgres"]["connection_uri"] = serde_json::Value::String(value.to_owned());
}
}
let engine = fixture_engine_with_document(fixture.path(), &source);
assert!(engine.is_ok());
let engine = match engine {
std::result::Result::Ok(value) => value,
std::result::Result::Err(_) => return,
};
let environment = crate::ConfigEnvironment::from_maps(std::collections::BTreeMap::new(), std::collections::BTreeMap::new());
let resolved = engine.load_resolved_store_config(std::option::Option::None, &environment);
assert!(resolved.is_err(), "Store URI without secret provenance must be rejected");
if let std::result::Result::Err(error) = resolved {
assert_eq!(error.code(), crate::ERROR_CODE_EFFECTIVE_CONFIG_INVALID);
assert!(!format!("{error:?}").contains("literal.invalid"));
assert!(!format!("{error:?}").contains("public.invalid"));
}
}
}
fn committed_engine() -> ksp_core_lib::Result<crate::ConfigDocumentEngine> {
let workspace = workspace_root();
let bootstrap = crate::ConfigBootstrapOptions::from_paths(workspace.join("config"), workspace.join("config/schemas"));
let bootstrap = match bootstrap {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let registry = crate::ConfigFileRegistry::defaults();
let registry = match registry {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
return std::result::Result::Ok(crate::ConfigDocumentEngine::new(bootstrap, registry));
}
fn fixture_engine_with_document(root: &std::path::Path, document: &serde_json::Value) -> ksp_core_lib::Result<crate::ConfigDocumentEngine> {
let config_root = root.join("config");
if let std::result::Result::Err(error) = std::fs::create_dir_all(config_root.as_path()) {
return std::result::Result::Err(
ksp_core_lib::Error::new(crate::ERROR_CODE_JSON_FILE_READ_FAILED, "test Config root cannot be created").with_source(error),
);
}
let bytes = serde_json::to_vec_pretty(document);
let bytes = match bytes {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => {
return std::result::Result::Err(
ksp_core_lib::Error::new(crate::ERROR_CODE_JSON_SYNTAX_INVALID, "test Store Config cannot be encoded").with_source(error),
);
},
};
let path = config_root.join(crate::DEFAULT_STD_STORE_FILENAME);
if let std::result::Result::Err(error) = std::fs::write(path.as_path(), bytes) {
return std::result::Result::Err(
ksp_core_lib::Error::new(crate::ERROR_CODE_JSON_FILE_READ_FAILED, "test Store Config cannot be written").with_source(error),
);
}
let bootstrap = crate::ConfigBootstrapOptions::from_paths(config_root, workspace_root().join("config/schemas"));
let bootstrap = match bootstrap {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let registry = crate::ConfigFileRegistry::defaults();
let registry = match registry {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
return std::result::Result::Ok(crate::ConfigDocumentEngine::new(bootstrap, registry));
}
fn committed_document_value() -> std::result::Result<serde_json::Value, serde_json::Error> {
return serde_json::from_str(include_str!("../../../config/std.store.json"));
}
fn workspace_root() -> std::path::PathBuf {
return std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../..");
}