v0.3.2-pre.009
This commit is contained in:
256
crates/ksp-store-lib/tests/hardening_completeness.rs
Normal file
256
crates/ksp-store-lib/tests/hardening_completeness.rs
Normal file
@@ -0,0 +1,256 @@
|
||||
// file: crates/ksp-store-lib/tests/hardening_completeness.rs
|
||||
// version: 1
|
||||
|
||||
#![warn(missing_docs)]
|
||||
#![deny(unreachable_pub)]
|
||||
#![forbid(unsafe_code)]
|
||||
|
||||
//! Hardening, exact-surface and feature-matrix canaries for the common Store facade.
|
||||
|
||||
const SECRET_CANARY: &str = "KSP-STORE-SECRET-CANARY-PRE009";
|
||||
|
||||
fn poll_ready<T>(future: impl std::future::Future<Output = T>) -> T {
|
||||
let mut future = std::boxed::Box::pin(future);
|
||||
let waker = std::task::Waker::noop();
|
||||
let mut context = std::task::Context::from_waker(waker);
|
||||
return match std::future::Future::poll(future.as_mut(), &mut context) {
|
||||
std::task::Poll::Ready(value) => value,
|
||||
std::task::Poll::Pending => panic!("Store hardening pre-I/O rejection unexpectedly became pending"),
|
||||
};
|
||||
}
|
||||
|
||||
fn valid_network() -> ksp_store_lib::RawNetworkId {
|
||||
return match ksp_store_lib::RawNetworkId::new("devnet") {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => panic!("valid hardening network rejected: {error:?}"),
|
||||
};
|
||||
}
|
||||
|
||||
fn hostile_settings(connection_uri: &str) -> ksp_store_lib::StoreSettings {
|
||||
let postgres = ksp_store_lib::PostgresStoreSettings::new(
|
||||
connection_uri,
|
||||
ksp_store_lib::PostgresPoolSettings::default(),
|
||||
ksp_store_lib::PostgresTlsMode::VerifyFull,
|
||||
ksp_store_lib::PostgresBootstrapSettings::default(),
|
||||
);
|
||||
return ksp_store_lib::StoreSettings::with_default_shutdown(valid_network(), ksp_store_lib::StoreBackendSettings::Postgres(postgres));
|
||||
}
|
||||
|
||||
fn public_reexport_names(source: &str) -> std::vec::Vec<&str> {
|
||||
let mut names = std::vec::Vec::new();
|
||||
for line in source.lines() {
|
||||
let trimmed = line.trim();
|
||||
if !trimmed.starts_with("pub use ") || !trimmed.ends_with(';') {
|
||||
continue;
|
||||
}
|
||||
let without_semicolon = trimmed.trim_end_matches(';');
|
||||
let name = match without_semicolon.rsplit("::").next() {
|
||||
std::option::Option::Some(value) => value,
|
||||
std::option::Option::None => continue,
|
||||
};
|
||||
names.push(name);
|
||||
}
|
||||
names.sort_unstable();
|
||||
return names;
|
||||
}
|
||||
|
||||
fn manifest_dependency_names(source: &str) -> std::vec::Vec<&str> {
|
||||
let dependencies_tail = match source.split("[dependencies]").nth(1) {
|
||||
std::option::Option::Some(value) => value,
|
||||
std::option::Option::None => return std::vec::Vec::new(),
|
||||
};
|
||||
let dependencies = match dependencies_tail.split("[lints]").next() {
|
||||
std::option::Option::Some(value) => value,
|
||||
std::option::Option::None => return std::vec::Vec::new(),
|
||||
};
|
||||
let mut names = std::vec::Vec::new();
|
||||
for line in dependencies.lines() {
|
||||
let content = match line.split('#').next() {
|
||||
std::option::Option::Some(value) => value.trim(),
|
||||
std::option::Option::None => continue,
|
||||
};
|
||||
if content.is_empty() {
|
||||
continue;
|
||||
}
|
||||
let key = match content.split('=').next() {
|
||||
std::option::Option::Some(value) => value.trim().trim_end_matches(".workspace"),
|
||||
std::option::Option::None => continue,
|
||||
};
|
||||
if !key.is_empty() {
|
||||
names.push(key);
|
||||
}
|
||||
}
|
||||
names.sort_unstable();
|
||||
return names;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pre_009_facade_modules_and_crate_root_exports_are_exact() {
|
||||
let crate_root = include_str!("../src/lib.rs");
|
||||
for required in ["mod constants;", "mod error;", "mod health;", "mod settings;", "mod store;"] {
|
||||
assert!(crate_root.contains(required), "missing Store facade module: {required}");
|
||||
}
|
||||
assert!(!crate_root.contains("pub mod "));
|
||||
let actual = public_reexport_names(crate_root);
|
||||
let mut expected = [
|
||||
"ERROR_CODE_BACKEND_CLOSED",
|
||||
"ERROR_CODE_BACKEND_NOT_COMPILED",
|
||||
"ERROR_CODE_BACKEND_OPEN_FAILED",
|
||||
"ERROR_CODE_POSTGRES_CONFIG_INVALID",
|
||||
"ERROR_CODE_POSTGRES_CONNECT_FAILED",
|
||||
"ERROR_CODE_POSTGRES_HEALTH_FAILED",
|
||||
"ERROR_CODE_POSTGRES_MIGRATION_FAILED",
|
||||
"ERROR_CODE_POSTGRES_MIGRATION_MISMATCH",
|
||||
"ERROR_CODE_POSTGRES_POOL_TIMEOUT",
|
||||
"ERROR_CODE_POSTGRES_SCHEMA_NEWER",
|
||||
"ERROR_CODE_POSTGRES_TLS_FAILED",
|
||||
"ERROR_CODE_RAW_CONFLICT",
|
||||
"ERROR_CODE_RAW_MODEL_INVALID",
|
||||
"ERROR_CODE_RAW_PAYLOAD_INVALID",
|
||||
"ERROR_CODE_RAW_PROVENANCE_INVALID",
|
||||
"ERROR_CODE_RAW_QUERY_INVALID",
|
||||
"ERROR_CODE_RAW_RETENTION_INVALID",
|
||||
"ERROR_CODE_SETTINGS_INVALID",
|
||||
"ERROR_CODE_SHUTDOWN_TIMEOUT",
|
||||
"Error",
|
||||
"ErrorCode",
|
||||
"ErrorContext",
|
||||
"MAX_RAW_ACCOUNT_DATA_BYTES",
|
||||
"MAX_RAW_CODE_BYTES",
|
||||
"MAX_RAW_PAGE_CURSOR_BYTES",
|
||||
"MAX_RAW_PAYLOAD_BYTES",
|
||||
"MAX_RAW_SOURCE_PAYLOAD_BYTES",
|
||||
"MAX_RAW_UNIX_MILLIS",
|
||||
"PostgresBootstrapSettings",
|
||||
"PostgresPoolSettings",
|
||||
"PostgresStoreSettings",
|
||||
"PostgresTlsMode",
|
||||
"Pubkey",
|
||||
"RawAccountObservation",
|
||||
"RawAccountObservationRead",
|
||||
"RawAccountObservationWrite",
|
||||
"RawAccountState",
|
||||
"RawAccountStateQuery",
|
||||
"RawAccountStateRead",
|
||||
"RawAccountStateReference",
|
||||
"RawAccountStateWrite",
|
||||
"RawAcquisitionOrigin",
|
||||
"RawAcquisitionProvenance",
|
||||
"RawAcquisitionWriteOutcome",
|
||||
"RawContentHash",
|
||||
"RawEntityWriteOutcome",
|
||||
"RawFormatId",
|
||||
"RawNetworkId",
|
||||
"RawObservationKey",
|
||||
"RawObservationWriteOutcome",
|
||||
"RawPage",
|
||||
"RawPageCursor",
|
||||
"RawPageLimit",
|
||||
"RawPageRequest",
|
||||
"RawPayload",
|
||||
"RawProvenanceCode",
|
||||
"RawRetentionState",
|
||||
"RawRetentionWriteOutcome",
|
||||
"RawSlotRange",
|
||||
"RawSortDirection",
|
||||
"RawTimestamp",
|
||||
"RawTransaction",
|
||||
"RawTransactionAcquisitionMode",
|
||||
"RawTransactionObservation",
|
||||
"RawTransactionObservationRead",
|
||||
"RawTransactionObservationWrite",
|
||||
"RawTransactionQuery",
|
||||
"RawTransactionRead",
|
||||
"RawTransactionReference",
|
||||
"RawTransactionRetentionRead",
|
||||
"RawTransactionRetentionTransition",
|
||||
"RawTransactionRetentionWrite",
|
||||
"RawTransactionSignature",
|
||||
"RawTransactionTombstone",
|
||||
"RawTransactionWrite",
|
||||
"Result",
|
||||
"Store",
|
||||
"StoreApiFuture",
|
||||
"StoreBackendKind",
|
||||
"StoreBackendSettings",
|
||||
"StoreHealthSnapshot",
|
||||
"StoreHealthState",
|
||||
"StoreRuntimeSnapshot",
|
||||
"StoreSettings",
|
||||
];
|
||||
expected.sort_unstable();
|
||||
assert_eq!(actual.as_slice(), expected.as_slice());
|
||||
assert_eq!(actual.len(), 84);
|
||||
return;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pre_009_facade_manifest_and_feature_contract_are_exact() {
|
||||
let manifest = include_str!("../Cargo.toml");
|
||||
assert!(manifest.contains("default = [\"postgres\"]"));
|
||||
assert!(manifest.contains("postgres = [\"dep:ksp-store-postgres-lib\"]"));
|
||||
let actual = manifest_dependency_names(manifest);
|
||||
let expected = ["ksp-logging-lib", "ksp-store-api", "ksp-store-postgres-lib"];
|
||||
assert_eq!(actual.as_slice(), expected.as_slice());
|
||||
for forbidden in ["tokio-postgres", "deadpool-postgres", "rustls", "sqlx", "ksp-config-lib", "ksp-onchain-transport-lib", "ksp-offchain-transport-lib"] {
|
||||
assert!(!manifest.contains(forbidden), "forbidden Store facade dependency detected: {forbidden}");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pre_009_secret_canary_never_crosses_settings_or_pre_io_error_debug() {
|
||||
let malformed = std::format!("not-a-postgresql-uri-{SECRET_CANARY}");
|
||||
let settings = hostile_settings(malformed.as_str());
|
||||
let rendered = std::format!("{settings:?}");
|
||||
assert!(!rendered.contains(SECRET_CANARY));
|
||||
assert!(rendered.contains("<redacted>"));
|
||||
let result = poll_ready(ksp_store_lib::Store::open(settings));
|
||||
let error = match result {
|
||||
std::result::Result::Err(value) => value,
|
||||
std::result::Result::Ok(_) => panic!("hostile Store settings unexpectedly opened"),
|
||||
};
|
||||
#[cfg(feature = "postgres")]
|
||||
assert_eq!(error.code(), ksp_store_lib::ERROR_CODE_POSTGRES_CONFIG_INVALID);
|
||||
#[cfg(not(feature = "postgres"))]
|
||||
assert_eq!(error.code(), ksp_store_lib::ERROR_CODE_BACKEND_NOT_COMPILED);
|
||||
assert!(!std::format!("{error}").contains(SECRET_CANARY));
|
||||
assert!(!std::format!("{error:?}").contains(SECRET_CANARY));
|
||||
return;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pre_009_facade_production_sources_keep_config_env_physical_sql_and_backend_handles_out() {
|
||||
let production = std::format!(
|
||||
"{}
|
||||
{}
|
||||
{}
|
||||
{}",
|
||||
include_str!("../src/error.rs"),
|
||||
include_str!("../src/health.rs"),
|
||||
include_str!("../src/settings.rs"),
|
||||
include_str!("../src/store.rs")
|
||||
);
|
||||
for forbidden in [
|
||||
"ksp_config_lib",
|
||||
"std::env",
|
||||
"dotenv",
|
||||
"PGHOST",
|
||||
"PGPORT",
|
||||
"PGUSER",
|
||||
"PGPASSWORD",
|
||||
".pgpass",
|
||||
"tokio_postgres::Client",
|
||||
"tokio_postgres::Row",
|
||||
"tokio_postgres::Statement",
|
||||
"deadpool_postgres::Pool",
|
||||
"sqlx::",
|
||||
"CREATE TABLE",
|
||||
"INSERT INTO",
|
||||
"UPDATE ",
|
||||
"DELETE FROM",
|
||||
] {
|
||||
assert!(!production.contains(forbidden), "forbidden facade ownership/runtime material detected: {forbidden}");
|
||||
}
|
||||
return;
|
||||
}
|
||||
220
crates/ksp-store-postgres-lib/tests/hardening_completeness.rs
Normal file
220
crates/ksp-store-postgres-lib/tests/hardening_completeness.rs
Normal file
@@ -0,0 +1,220 @@
|
||||
// file: crates/ksp-store-postgres-lib/tests/hardening_completeness.rs
|
||||
// version: 1
|
||||
|
||||
#![warn(missing_docs)]
|
||||
#![deny(unreachable_pub)]
|
||||
#![forbid(unsafe_code)]
|
||||
|
||||
//! Hardening, exact-surface and scope canaries for the physical PostgreSQL Store backend.
|
||||
|
||||
const SECRET_CANARY: &str = "KSP-POSTGRES-SECRET-CANARY-PRE009";
|
||||
|
||||
fn poll_ready<T>(future: impl std::future::Future<Output = T>) -> T {
|
||||
let mut future = std::boxed::Box::pin(future);
|
||||
let waker = std::task::Waker::noop();
|
||||
let mut context = std::task::Context::from_waker(waker);
|
||||
return match std::future::Future::poll(future.as_mut(), &mut context) {
|
||||
std::task::Poll::Ready(value) => value,
|
||||
std::task::Poll::Pending => panic!("PostgreSQL hardening pre-I/O rejection unexpectedly became pending"),
|
||||
};
|
||||
}
|
||||
|
||||
fn network() -> ksp_store_api::RawNetworkId {
|
||||
return match ksp_store_api::RawNetworkId::new("devnet") {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => panic!("valid backend hardening network rejected: {error:?}"),
|
||||
};
|
||||
}
|
||||
|
||||
fn settings(connection_uri: &str, tls_mode: ksp_store_postgres_lib::PostgresBackendTlsMode) -> ksp_store_postgres_lib::PostgresBackendSettings {
|
||||
return ksp_store_postgres_lib::PostgresBackendSettings::new(
|
||||
network(),
|
||||
connection_uri,
|
||||
8,
|
||||
std::time::Duration::from_secs(10),
|
||||
std::time::Duration::from_secs(5),
|
||||
std::time::Duration::from_secs(10),
|
||||
std::time::Duration::from_secs(5),
|
||||
tls_mode,
|
||||
true,
|
||||
std::time::Duration::from_secs(30),
|
||||
std::time::Duration::from_secs(10),
|
||||
);
|
||||
}
|
||||
|
||||
fn public_reexport_names(source: &str) -> std::vec::Vec<&str> {
|
||||
let mut names = std::vec::Vec::new();
|
||||
for line in source.lines() {
|
||||
let trimmed = line.trim();
|
||||
if !trimmed.starts_with("pub use ") || !trimmed.ends_with(';') {
|
||||
continue;
|
||||
}
|
||||
let without_semicolon = trimmed.trim_end_matches(';');
|
||||
let name = match without_semicolon.rsplit("::").next() {
|
||||
std::option::Option::Some(value) => value,
|
||||
std::option::Option::None => continue,
|
||||
};
|
||||
names.push(name);
|
||||
}
|
||||
names.sort_unstable();
|
||||
return names;
|
||||
}
|
||||
|
||||
fn manifest_dependency_names(source: &str) -> std::vec::Vec<&str> {
|
||||
let dependencies_tail = match source.split("[dependencies]").nth(1) {
|
||||
std::option::Option::Some(value) => value,
|
||||
std::option::Option::None => return std::vec::Vec::new(),
|
||||
};
|
||||
let dependencies = match dependencies_tail.split("[lints]").next() {
|
||||
std::option::Option::Some(value) => value,
|
||||
std::option::Option::None => return std::vec::Vec::new(),
|
||||
};
|
||||
let mut names = std::vec::Vec::new();
|
||||
for line in dependencies.lines() {
|
||||
let content = match line.split('#').next() {
|
||||
std::option::Option::Some(value) => value.trim(),
|
||||
std::option::Option::None => continue,
|
||||
};
|
||||
if content.is_empty() {
|
||||
continue;
|
||||
}
|
||||
let key = match content.split('=').next() {
|
||||
std::option::Option::Some(value) => value.trim().trim_end_matches(".workspace"),
|
||||
std::option::Option::None => continue,
|
||||
};
|
||||
if !key.is_empty() {
|
||||
names.push(key);
|
||||
}
|
||||
}
|
||||
names.sort_unstable();
|
||||
return names;
|
||||
}
|
||||
|
||||
fn assert_pre_io_rejection(connection_uri: &str, tls_mode: ksp_store_postgres_lib::PostgresBackendTlsMode, expected_phase: &str) {
|
||||
let settings = settings(connection_uri, tls_mode);
|
||||
let rendered_settings = std::format!("{settings:?}");
|
||||
assert!(!rendered_settings.contains(SECRET_CANARY));
|
||||
assert!(rendered_settings.contains("<redacted>"));
|
||||
let result = poll_ready(ksp_store_postgres_lib::PostgresBackend::open(settings));
|
||||
let error = match result {
|
||||
std::result::Result::Err(value) => value,
|
||||
std::result::Result::Ok(_) => panic!("hostile PostgreSQL settings unexpectedly opened"),
|
||||
};
|
||||
assert_eq!(error.kind(), ksp_store_postgres_lib::PostgresBackendErrorKind::ConfigInvalid);
|
||||
assert_eq!(error.phase(), expected_phase);
|
||||
assert!(!std::format!("{error:?}").contains(SECRET_CANARY));
|
||||
return;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pre_009_backend_modules_exports_and_manifest_dependencies_are_exact() {
|
||||
let crate_root = include_str!("../src/lib.rs");
|
||||
for required in ["mod constants;", "mod error;", "mod health;", "mod migration;", "mod runtime;"] {
|
||||
assert!(crate_root.contains(required), "missing PostgreSQL backend module: {required}");
|
||||
}
|
||||
assert!(!crate_root.contains("pub mod "));
|
||||
let actual_exports = public_reexport_names(crate_root);
|
||||
let mut expected_exports = [
|
||||
"PostgresBackend",
|
||||
"PostgresBackendError",
|
||||
"PostgresBackendErrorKind",
|
||||
"PostgresBackendHealthSnapshot",
|
||||
"PostgresBackendRuntimeSnapshot",
|
||||
"PostgresBackendSettings",
|
||||
"PostgresBackendTlsMode",
|
||||
];
|
||||
expected_exports.sort_unstable();
|
||||
assert_eq!(actual_exports.as_slice(), expected_exports.as_slice());
|
||||
assert_eq!(actual_exports.len(), 7);
|
||||
let manifest = include_str!("../Cargo.toml");
|
||||
let actual_dependencies = manifest_dependency_names(manifest);
|
||||
let expected_dependencies = [
|
||||
"deadpool-postgres",
|
||||
"ksp-logging-lib",
|
||||
"ksp-store-api",
|
||||
"rustls",
|
||||
"rustls-native-certs",
|
||||
"sha2",
|
||||
"tokio",
|
||||
"tokio-postgres",
|
||||
"tokio-postgres-rustls",
|
||||
];
|
||||
assert_eq!(actual_dependencies.as_slice(), expected_dependencies.as_slice());
|
||||
return;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pre_009_hostile_uri_matrix_is_rejected_before_io_without_secret_echo() {
|
||||
let malformed = std::format!("not-a-postgresql-uri-{SECRET_CANARY}");
|
||||
assert_pre_io_rejection(malformed.as_str(), ksp_store_postgres_lib::PostgresBackendTlsMode::Disabled, "connection_uri");
|
||||
let oversized = std::format!("{}{SECRET_CANARY}", "x".repeat(4_097));
|
||||
assert_pre_io_rejection(oversized.as_str(), ksp_store_postgres_lib::PostgresBackendTlsMode::Disabled, "connection_uri");
|
||||
let hostaddr_only = std::format!("hostaddr=127.0.0.1 user=operator password={SECRET_CANARY} dbname=ksp");
|
||||
assert_pre_io_rejection(hostaddr_only.as_str(), ksp_store_postgres_lib::PostgresBackendTlsMode::VerifyFull, "tls_server_identity");
|
||||
let server_options = std::format!("host=localhost user=operator password={SECRET_CANARY} dbname=ksp options='-c application_name={SECRET_CANARY}'");
|
||||
assert_pre_io_rejection(server_options.as_str(), ksp_store_postgres_lib::PostgresBackendTlsMode::Disabled, "server_options");
|
||||
return;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pre_009_backend_error_bridge_cannot_retain_external_error_or_secret_text() {
|
||||
let error_source = include_str!("../src/error.rs");
|
||||
assert!(error_source.contains("kind: PostgresBackendErrorKind"));
|
||||
assert!(error_source.contains("phase: &'static str"));
|
||||
for forbidden in ["String", "source:", "message:", "tokio_postgres::Error", "deadpool_postgres::PoolError"] {
|
||||
assert!(!error_source.contains(forbidden), "backend error type can retain forbidden external material: {forbidden}");
|
||||
}
|
||||
let runtime = include_str!("../src/runtime.rs");
|
||||
assert!(runtime.contains("deadpool_postgres::PoolError::Backend(_)"));
|
||||
assert!(!runtime.contains("deadpool_postgres::PoolError::Backend(error)"));
|
||||
for source in [runtime, include_str!("../src/migration.rs"), include_str!("../src/health.rs")] {
|
||||
for forbidden in ["format!(\"{error", "format!(\"{error:?", "error = ?", "error = %"] {
|
||||
assert!(!source.contains(forbidden), "backend source renders external error material: {forbidden}");
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pre_009_backend_has_no_env_bypass_or_business_persistence_capability() {
|
||||
let production = std::format!(
|
||||
"{}
|
||||
{}
|
||||
{}
|
||||
{}
|
||||
{}",
|
||||
include_str!("../src/error.rs"),
|
||||
include_str!("../src/health.rs"),
|
||||
include_str!("../src/lib.rs"),
|
||||
include_str!("../src/migration.rs"),
|
||||
include_str!("../src/runtime.rs")
|
||||
);
|
||||
for forbidden in [
|
||||
"std::env",
|
||||
"dotenv",
|
||||
"KSP_SECRET_",
|
||||
"KSPB_",
|
||||
"PGHOST",
|
||||
"PGPORT",
|
||||
"PGUSER",
|
||||
"PGPASSWORD",
|
||||
".pgpass",
|
||||
".postgresql/",
|
||||
"sslrootcert",
|
||||
"sslcert",
|
||||
"sslkey",
|
||||
"ksp_store_lib",
|
||||
"ksp_config_lib",
|
||||
"sqlx::",
|
||||
"impl ksp_store_api::RawTransaction",
|
||||
"impl ksp_store_api::RawAccount",
|
||||
] {
|
||||
assert!(!production.contains(forbidden), "forbidden backend ownership/capability material detected: {forbidden}");
|
||||
}
|
||||
let bootstrap_sql = include_str!("../migrations/V000__bootstrap.sql");
|
||||
assert!(bootstrap_sql.contains("ksp_store_schema_migrations"));
|
||||
for forbidden in ["RawTransaction", "RawAccountState", "raw_transaction", "raw_account", "CORE", "DECODE", "SPECIALIZED"] {
|
||||
assert!(!bootstrap_sql.contains(forbidden), "business schema leaked into foundation migration: {forbidden}");
|
||||
}
|
||||
return;
|
||||
}
|
||||
Reference in New Issue
Block a user