package_boundary.rs (10204B)
1 use std::{fs, path::Path}; 2 3 fn read(path: &Path) -> String { 4 fs::read_to_string(path).unwrap_or_else(|error| panic!("{}: {error}", path.display())) 5 } 6 7 #[test] 8 fn storage_package_keeps_one_sqlite_authority_and_a_sealed_public_surface() { 9 let crate_root = Path::new(env!("CARGO_MANIFEST_DIR")); 10 let workspace_root = crate_root.join("../.."); 11 let manifest = read(&crate_root.join("Cargo.toml")); 12 let workspace_manifest = read(&workspace_root.join("Cargo.toml")); 13 let lock = read(&workspace_root.join("Cargo.lock")); 14 let root_source = read(&crate_root.join("src/lib.rs")); 15 let contract_source = read(&crate_root.join("src/contract.rs")); 16 let database_source = read(&crate_root.join("src/db.rs")); 17 let evidence_source = read(&crate_root.join("src/availability_evidence.rs")); 18 let journal_source = read(&crate_root.join("src/journal.rs")); 19 let keyring_source = read(&crate_root.join("src/os_keyring.rs")); 20 let api = read(&workspace_root.join("compatibility/harvestcircle-storage-api-v3.txt")); 21 22 for forbidden in ["rusqlite", "refinery", "hmac", "rustix"] { 23 assert!( 24 !manifest.contains(forbidden), 25 "storage manifest reintroduced direct {forbidden} authority" 26 ); 27 } 28 assert!(manifest.contains("radroots_service_sqlite.workspace = true")); 29 assert!(manifest.contains("radroots_event = { workspace = true, features = [\"std\"] }")); 30 assert!( 31 manifest.contains( 32 "radroots_event_codec = { workspace = true, features = [\"std\", \"json\"] }" 33 ) 34 ); 35 assert!(manifest.contains("sqlx.workspace = true")); 36 assert!(!manifest.contains("\nkeyring =")); 37 assert!(manifest.contains( 38 "secret-service = { version = \"=5.1.0\", features = [\"rt-tokio-crypto-rust\"] }" 39 )); 40 assert!(!manifest.contains("features = [\"crypto-rust\"]")); 41 assert!(manifest.contains("security-framework = \"=3.7.0\"")); 42 assert!(manifest.contains("security-framework-sys = \"=2.17.0\"")); 43 assert!(workspace_manifest.contains("sqlx = { version = \"=0.9.0\"")); 44 for forbidden_package in ["rusqlite", "refinery"] { 45 assert!( 46 !lock.contains(&format!("\nname = \"{forbidden_package}\"\n")), 47 "lock contains forbidden SQLite package {forbidden_package}" 48 ); 49 } 50 51 for module in [ 52 "availability_evidence", 53 "backup", 54 "contract", 55 "db", 56 "identities", 57 "identity_namespace", 58 "installation", 59 "journal", 60 "os_keyring", 61 "profiles", 62 ] { 63 assert!(root_source.contains(&format!("mod {module};"))); 64 assert!(!root_source.contains(&format!("pub mod {module};"))); 65 } 66 assert!(!root_source.contains("harvestcircle_initial_schema_sql")); 67 assert!(!keyring_source.contains("PoisonError::into_inner")); 68 assert!(!keyring_source.contains("set_password")); 69 assert!(keyring_source.contains("add_generic_password")); 70 assert!(keyring_source.contains("CREDENTIAL_OPERATION_ATTRIBUTE")); 71 assert!(keyring_source.contains("false,\n \"application/octet-stream\"")); 72 let readonly_verification = keyring_source 73 .split_once(" fn verify<'a>(") 74 .and_then(|(_, source)| source.split_once("\n fn load(")) 75 .map(|(body, _)| body) 76 .expect("request-bound read-only verification method"); 77 for required in [ 78 "request_id: &'a DurableRequestId", 79 "public_key: PublicKey", 80 "secret: SecretKeyInput", 81 "self.operation()?", 82 "Zeroizing::new(platform_read(&account).map_err(map_read_error)?)", 83 "verify_replay_binding(request_id, &secret, encoded.as_slice())", 84 ] { 85 assert!( 86 readonly_verification.contains(required), 87 "read-only custody boundary is missing {required}" 88 ); 89 } 90 for forbidden in ["platform_create(", "platform_delete(", ".put(", ".delete("] { 91 assert!( 92 !readonly_verification.contains(forbidden), 93 "verification mutates custody through {forbidden}" 94 ); 95 } 96 assert!(keyring_source.contains("verify_existing_replay(request_id, secret, encoded).map_err")); 97 assert!(keyring_source.contains("SafeErrorCode::InvalidApplicationState")); 98 let envelope_comparison = keyring_source 99 .split_once("fn verify_existing_replay(") 100 .and_then(|(_, source)| source.split_once("\nfn verify_replay_binding(")) 101 .map(|(body, _)| body) 102 .expect("shared complete envelope comparison"); 103 for required in [ 104 "decode_credential(encoded)?", 105 "existing_request == *request_id", 106 "existing_secret", 107 "secret.with_exposed_secret(|expected| value == expected)", 108 "Err(credential_exists())", 109 ] { 110 assert!( 111 envelope_comparison.contains(required), 112 "complete custody binding is missing {required}" 113 ); 114 } 115 assert!(!database_source.contains("pub fn host")); 116 assert!(!database_source.contains("pub const fn host")); 117 for forbidden in [ 118 "SqlitePool", 119 "SqliteConnection", 120 "DELETE FROM availability_versions", 121 "DELETE FROM public_payload_usage", 122 "SecretKey", 123 "OsKeyringSecretStore", 124 "account_identities", 125 "local_signer_bindings", 126 "profile_cache", 127 ] { 128 assert!( 129 !evidence_source.contains(forbidden), 130 "public evidence crossed authority through {forbidden}" 131 ); 132 } 133 assert!(evidence_source.contains("verify_nip01_event(")); 134 assert!(evidence_source.contains("Nip01EventWire::parse_json_unverified(")); 135 136 for required in [ 137 "pub struct harvestcircle_storage::Database", 138 "pub async fn harvestcircle_storage::Database::open", 139 "pub async fn harvestcircle_storage::Database::close", 140 "pub async fn harvestcircle_storage::Database::retain_availability_version", 141 "pub async fn harvestcircle_storage::Database::load_availability_version", 142 "pub async fn harvestcircle_storage::Database::capture_online_backup", 143 "pub async fn harvestcircle_storage::Database::restore_verified_backup", 144 "pub struct harvestcircle_storage::VerifiedHarvestCircleBackup", 145 "pub fn harvestcircle_storage::verify_harvestcircle_backup", 146 "impl harvestcircle_application::ports::DurableOperationRepository for harvestcircle_storage::Database", 147 "harvestcircle_application::ports::BoxFuture", 148 "pub fn harvestcircle_storage::OsKeyringSecretStore::contains(&self, harvestcircle_domain::key::PublicKey) -> harvestcircle_application::ports::BoxFuture", 149 "pub fn harvestcircle_storage::OsKeyringSecretStore::put<'a>(&'a self, &'a harvestcircle_application::ports::DurableRequestId, harvestcircle_domain::key::PublicKey, harvestcircle_domain::key::SecretKeyInput) -> harvestcircle_application::ports::BoxFuture<'a", 150 "pub fn harvestcircle_storage::OsKeyringSecretStore::verify<'a>(&'a self, &'a harvestcircle_application::ports::DurableRequestId, harvestcircle_domain::key::PublicKey, harvestcircle_domain::key::SecretKeyInput) -> harvestcircle_application::ports::BoxFuture<'a", 151 "pub fn harvestcircle_storage::OsKeyringSecretStore::delete<'a>(&'a self, &'a harvestcircle_application::ports::DurableRequestId, harvestcircle_domain::key::PublicKey) -> harvestcircle_application::ports::BoxFuture<'a", 152 "pub fn harvestcircle_storage::harvestcircle_migration_catalog()", 153 "pub fn harvestcircle_storage::harvestcircle_schema_catalog()", 154 "pub const harvestcircle_storage::HARVESTCIRCLE_DURABLE_OPERATION_CAPACITY: usize", 155 "pub const harvestcircle_storage::HARVESTCIRCLE_DURABLE_OPERATION_CLEANUP_BATCH: usize", 156 "pub const harvestcircle_storage::HARVESTCIRCLE_TERMINAL_RECEIPT_RETENTION_SECONDS: i64", 157 ] { 158 assert!(api.contains(required), "API baseline is missing {required}"); 159 } 160 for forbidden in [ 161 "rusqlite::", 162 "refinery::", 163 "sqlx::", 164 "OperationJournal", 165 "harvestcircle_initial_schema_sql", 166 "SELECT_AVAILABILITY_VERSION_SQL", 167 "decode_availability_row", 168 "retain_availability_version_on", 169 "ServiceSqliteTransaction", 170 "VerifiedServiceBackup", 171 "StagedServiceRestore", 172 "verify_backup_bundle", 173 "stage_verified_restore", 174 "finalize_staged_restore", 175 "repair", 176 "preflight", 177 ] { 178 assert!( 179 !api.contains(forbidden), 180 "API baseline exposes forbidden surface {forbidden}" 181 ); 182 } 183 184 for required in [ 185 "pub const HARVESTCIRCLE_STATE_SCHEMA_VERSION: u32 = 3;", 186 "pub const HARVESTCIRCLE_UNFINISHED_DURABLE_OPERATION_CAPACITY: usize = 1_024;", 187 "pub const HARVESTCIRCLE_DURABLE_OPERATION_CAPACITY: usize = 4_096;", 188 "pub const HARVESTCIRCLE_DURABLE_OPERATION_CLEANUP_BATCH: usize = 256;", 189 "pub const HARVESTCIRCLE_TERMINAL_RECEIPT_RETENTION_SECONDS: i64 = 7 * 24 * 60 * 60;", 190 "bound_durable_operation_receipts", 191 "completed_at_unix_s", 192 "durable_operations_receipt_insert_guard", 193 "durable_operations_receipt_update_guard", 194 "add_verified_listing_evidence", 195 "CREATE TABLE availability_versions", 196 "CREATE TABLE public_payload_usage", 197 ] { 198 assert!( 199 contract_source.contains(required), 200 "storage contract is missing {required}" 201 ); 202 } 203 for required in [ 204 "LIMIT 1025", 205 "LIMIT 4097", 206 "LIMIT 256", 207 "completed_at_unix_s < ?", 208 "completed_at_unix_s = ?", 209 ] { 210 assert!( 211 journal_source.contains(required), 212 "journal enforcement is missing {required}" 213 ); 214 } 215 for forbidden in [ 216 "DELETE FROM durable_operations WHERE terminal_outcome IS NOT NULL", 217 "DELETE FROM durable_operations WHERE completed_at_unix_s IS NOT NULL;", 218 "ORDER BY completed_at_unix_s DESC", 219 ] { 220 assert!( 221 !journal_source.contains(forbidden), 222 "journal reintroduced unbounded or in-window eviction: {forbidden}" 223 ); 224 } 225 }