v0.2.12-pre.009
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "ksp-app-solprices-desk",
|
||||
"private": true,
|
||||
"version": "0.2.12-pre.7",
|
||||
"version": "0.2.12-pre.9",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
// file: crates/ksp-app-solprices-desk/src/market_price_runtime.rs
|
||||
// version: 3
|
||||
// version: 4
|
||||
|
||||
//! Provider-neutral market-price presentation runtime owned by SOL Prices Desk.
|
||||
|
||||
use ts_rs::TS; // rust-rules: trait-import
|
||||
|
||||
const MARKET_PRICE_REFRESH_MAX_PROVIDER_IDS: usize = 64;
|
||||
|
||||
/// Safe provider-neutral row projected to the SOL Prices Desk frontend.
|
||||
#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
@@ -534,6 +536,16 @@ fn lock_presentation(
|
||||
}
|
||||
|
||||
fn parse_provider_ids(provider_ids: std::vec::Vec<String>) -> ksp_core_lib::Result<std::vec::Vec<ksp_offchain_transport_lib::MarketPriceProviderId>> {
|
||||
if provider_ids.is_empty() || provider_ids.len() > MARKET_PRICE_REFRESH_MAX_PROVIDER_IDS {
|
||||
return std::result::Result::Err(
|
||||
ksp_core_lib::Error::new(
|
||||
crate::ERROR_CODE_MARKET_PRICE_SELECTION_INVALID,
|
||||
"SOL Prices Desk market-price refresh selection has an invalid provider count",
|
||||
)
|
||||
.with_context("provider_count", provider_ids.len().to_string())
|
||||
.with_context("max_provider_count", MARKET_PRICE_REFRESH_MAX_PROVIDER_IDS.to_string()),
|
||||
);
|
||||
}
|
||||
let mut parsed = std::vec::Vec::with_capacity(provider_ids.len());
|
||||
for provider_id in provider_ids {
|
||||
let provider_id = ksp_offchain_transport_lib::MarketPriceProviderId::new(provider_id);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"$schema": "https://schema.tauri.app/config/2",
|
||||
"productName": "KSP SOL Prices Desk",
|
||||
"version": "0.2.12-pre.7",
|
||||
"version": "0.2.12-pre.9",
|
||||
"identifier": "com.sasedev.ksp-app-solprices-desk",
|
||||
"build": {
|
||||
"beforeDevCommand": {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: crates/ksp-app-solprices-desk/tests/desktop_contract.rs
|
||||
// version: 7
|
||||
// version: 8
|
||||
|
||||
//! Desktop scaffold, shared-template and Config packaging contract audits for SOL Prices Desk `0.2.12`.
|
||||
|
||||
@@ -80,6 +80,7 @@ fn pre_002_shell_uses_reserved_ports_windows_and_owned_backend_paths() {
|
||||
let package_version = package.pointer("/version").and_then(serde_json::Value::as_str);
|
||||
assert_packaged_version_floor(package_version, "package.json");
|
||||
assert_eq!(tauri_version, package_version, "desktop package metadata versions must remain synchronized");
|
||||
assert_eq!(tauri_version, std::option::Option::Some(env!("CARGO_PKG_VERSION")), "SOL Prices Desk package metadata must match the current Cargo release");
|
||||
assert_eq!(tauri.pointer("/build/devUrl").and_then(serde_json::Value::as_str), std::option::Option::Some("http://localhost:1434"));
|
||||
assert_eq!(tauri.pointer("/build/beforeDevCommand/script").and_then(serde_json::Value::as_str), std::option::Option::Some("npm run dev"));
|
||||
assert_eq!(tauri.pointer("/build/beforeDevCommand/cwd").and_then(serde_json::Value::as_str), std::option::Option::Some("."));
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: crates/ksp-app-solprices-desk/tests/desktop_security.rs
|
||||
// version: 7
|
||||
// version: 8
|
||||
|
||||
//! Security, ownership and frontend instrumentation canaries for SOL Prices Desk.
|
||||
|
||||
@@ -186,3 +186,16 @@ fn pre_007_remains_manual_without_browser_persistence_or_price_scheduler() {
|
||||
assert!(!main.contains(forbidden), "pre.007 must remain manual and backend-owned: {forbidden}");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pre_009_hardening_bounds_hostile_batches_and_preserves_manual_backend_owned_refresh() {
|
||||
let root = app_root();
|
||||
let runtime = read_text(root.join("src/market_price_runtime.rs").as_path());
|
||||
assert!(runtime.contains("const MARKET_PRICE_REFRESH_MAX_PROVIDER_IDS: usize = 64;"));
|
||||
assert!(runtime.contains("provider_ids.is_empty() || provider_ids.len() > MARKET_PRICE_REFRESH_MAX_PROVIDER_IDS"));
|
||||
assert!(runtime.contains("ERROR_CODE_MARKET_PRICE_SELECTION_INVALID"));
|
||||
let main = read_text(root.join("frontend/ts/main.ts").as_path());
|
||||
for forbidden in ["setInterval(", "setTimeout(", "requestAnimationFrame(", "fetch(", "XMLHttpRequest", "localStorage", "sessionStorage"] {
|
||||
assert!(!main.contains(forbidden), "release hardening must preserve manual backend-owned refresh: {forbidden}");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
// file: crates/ksp-app-solprices-desk/tests/market_price_composition_live_smoke.rs
|
||||
// version: 1
|
||||
|
||||
//! Opt-in live smoke proving SOL Prices Desk composite -> Config -> generic MarketPriceService composition.
|
||||
|
||||
fn workspace_engine() -> ksp_core_lib::Result<ksp_config_lib::ConfigDocumentEngine> {
|
||||
let workspace = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../..");
|
||||
let bootstrap = ksp_config_lib::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 = ksp_config_lib::ConfigFileRegistry::defaults();
|
||||
return match registry {
|
||||
std::result::Result::Ok(value) => std::result::Result::Ok(ksp_config_lib::ConfigDocumentEngine::new(bootstrap, value)),
|
||||
std::result::Result::Err(error) => std::result::Result::Err(error),
|
||||
};
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "current_thread")]
|
||||
#[ignore = "opt-in live SOL Prices Desk composition smoke; resolves the committed public_keyless composite and performs external SOL/USD HTTPS refreshes"]
|
||||
async fn committed_solprices_composite_refreshes_at_least_one_keyless_provider() {
|
||||
let engine = workspace_engine();
|
||||
assert!(engine.is_ok(), "workspace Config engine should be constructible");
|
||||
let engine = match engine {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(_) => return,
|
||||
};
|
||||
let file_id = ksp_config_lib::ConfigFileId::new(ksp_config_lib::FILE_ID_COMPOSITE_KSP_APP_SOLPRICES_DESK);
|
||||
assert!(file_id.is_ok(), "SOL Prices Desk composite file_id should be valid");
|
||||
let file_id = match file_id {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(_) => return,
|
||||
};
|
||||
let composite = engine.load_resolved_composite(&file_id, std::option::Option::None);
|
||||
assert!(composite.is_ok(), "committed SOL Prices Desk composite should resolve");
|
||||
let composite = match composite {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(_) => return,
|
||||
};
|
||||
assert_eq!(composite.profile_id(), "public_keyless");
|
||||
let component = composite.component("offchain_transport");
|
||||
assert!(component.is_some(), "SOL Prices Desk composite should contain Off-chain Transport");
|
||||
let component = match component {
|
||||
std::option::Option::Some(value) => value,
|
||||
std::option::Option::None => return,
|
||||
};
|
||||
let environment = ksp_config_lib::ConfigEnvironment::load();
|
||||
assert!(environment.is_ok(), "Config-owned environment snapshot should load");
|
||||
let environment = match environment {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(_) => return,
|
||||
};
|
||||
let resolved = engine.resolve_offchain_transport_config_profile(component.resolved(), &environment);
|
||||
assert!(resolved.is_ok(), "composite-selected public_keyless Off-chain Transport should map");
|
||||
let resolved = match resolved {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(_) => return,
|
||||
};
|
||||
assert_eq!(resolved.profile_id(), "public_keyless");
|
||||
assert_eq!(resolved.selection_source(), ksp_config_lib::ConfigProfileSelectionSource::Composite);
|
||||
let registry = resolved.service().registry();
|
||||
assert_eq!(registry.len(), 8);
|
||||
let outcomes = resolved.service().refresh_all().await;
|
||||
assert!(outcomes.is_ok(), "generic public_keyless refresh_all should complete without provider-specific application branching");
|
||||
let outcomes = match outcomes {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(_) => return,
|
||||
};
|
||||
assert_eq!(outcomes.len(), registry.len());
|
||||
let refreshed_count = outcomes.iter().filter(|outcome| return outcome.refreshed()).count();
|
||||
assert!(refreshed_count > 0, "at least one public_keyless provider should produce one live SOL/USD observation");
|
||||
for outcome in outcomes {
|
||||
assert!(registry.entry(outcome.provider_id()).is_some(), "live outcome provider must belong to the generic registry");
|
||||
if let std::option::Option::Some(observation) = outcome.observation() {
|
||||
assert_eq!(observation.pair(), ksp_offchain_transport_lib::MarketPricePair::SolUsd);
|
||||
assert_eq!(observation.provider_id(), outcome.provider_id());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: crates/ksp-app-solprices-desk/unit_tests/market_price_runtime.rs
|
||||
// version: 3
|
||||
// version: 4
|
||||
|
||||
fn descriptor() -> std::option::Option<ksp_offchain_transport_lib::MarketPriceProviderDescriptor> {
|
||||
let provider_id = ksp_offchain_transport_lib::MarketPriceProviderId::new("test-provider");
|
||||
@@ -278,3 +278,25 @@ fn batch_loading_validation_rejects_in_flight_provider_without_marking_other_row
|
||||
}
|
||||
return std::result::Result::Ok(());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hostile_batch_size_is_rejected_before_provider_id_parsing() {
|
||||
let provider_ids = (0..=super::MARKET_PRICE_REFRESH_MAX_PROVIDER_IDS)
|
||||
.map(|index| return std::format!("invalid provider payload {index}"))
|
||||
.collect::<std::vec::Vec<_>>();
|
||||
let result = super::parse_provider_ids(provider_ids);
|
||||
assert!(result.is_err());
|
||||
if let std::result::Result::Err(error) = result {
|
||||
assert_eq!(error.code(), crate::ERROR_CODE_MARKET_PRICE_SELECTION_INVALID);
|
||||
assert_eq!(error.context().len(), 2);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn empty_batch_is_rejected_at_the_application_boundary() {
|
||||
let result = super::parse_provider_ids(std::vec::Vec::new());
|
||||
assert!(result.is_err());
|
||||
if let std::result::Result::Err(error) = result {
|
||||
assert_eq!(error.code(), crate::ERROR_CODE_MARKET_PRICE_SELECTION_INVALID);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user