services_hardening_publication_attempt_evidence_contract.rs (3047B)
1 #![forbid(unsafe_code)] 2 3 use serde_json::json; 4 5 const CONTRACT: &str = 6 include_str!("../contracts/services_hardening/publication_attempt_evidence.v1.json"); 7 const SOURCE: &str = include_str!("../src/publication_attempt.rs"); 8 const ROOT: &str = include_str!("../src/lib.rs"); 9 10 #[test] 11 fn exact_target_and_attempt_vocabularies_are_closed() { 12 let contract: serde_json::Value = serde_json::from_str(CONTRACT).expect("contract JSON"); 13 assert_eq!( 14 contract["schema"], 15 "radroots.rhi.publication-attempt-evidence" 16 ); 17 assert_eq!(contract["schema_version"], 1); 18 assert_eq!(contract["contract_version"], 1); 19 assert_eq!( 20 contract["target_states"], 21 json!([ 22 "pending", 23 "submitted", 24 "accepted", 25 "rejected", 26 "rate_limited", 27 "auth_required", 28 "failed", 29 "unknown" 30 ]) 31 ); 32 assert_eq!( 33 contract["attempt_outcomes"], 34 json!([ 35 "submitted", 36 "accepted", 37 "rejected", 38 "rate_limited", 39 "auth_required", 40 "failed", 41 "unknown" 42 ]) 43 ); 44 assert_eq!(contract["bounds"]["target_ordinal"]["maximum"], 31); 45 assert_eq!(contract["bounds"]["attempt_number"]["maximum"], 100); 46 assert_eq!( 47 contract["bounds"]["unix_milliseconds"]["maximum"], 48 9_223_372_036_854_775_807_u64 49 ); 50 assert_eq!(contract["evidence"]["raw_relay_result_or_error"], false); 51 assert_eq!( 52 contract["semantics"]["submission_alone_proves_delivery"], 53 false 54 ); 55 assert_eq!(contract["effects"]["sqlite_read_or_mutation"], false); 56 assert_eq!(contract["effects"]["relay_or_network"], false); 57 } 58 59 #[test] 60 fn pure_model_has_no_premature_workflow_or_effect_authority() { 61 for required in [ 62 "pub enum RhiPublicationTargetState", 63 "pub enum RhiPublicationAttemptOutcome", 64 "pub struct RhiPublicationAttemptEvidence", 65 "pub struct RhiPublicationAttemptId", 66 "pub struct RhiPublicationUnixMilliseconds", 67 "radroots.rhi.publication_attempt.v1\\0", 68 "publication.outbox_id()", 69 "publication.event_sha256()", 70 "digest.update(u32::from(target_ordinal).to_be_bytes())", 71 "digest.update(u32::from(attempt_number).to_be_bytes())", 72 ] { 73 assert!( 74 SOURCE.contains(required), 75 "missing evidence guard {required}" 76 ); 77 } 78 for forbidden in [ 79 "sqlx::", 80 "radroots_transport", 81 "EventSink", 82 "SystemTime", 83 "std::fs", 84 "std::net", 85 "tokio::spawn", 86 "spawn_blocking", 87 "serde_json", 88 "publish(", 89 "send(", 90 "from_committed_parts", 91 ] { 92 assert!( 93 !SOURCE.contains(forbidden), 94 "attempt evidence gained forbidden authority {forbidden}" 95 ); 96 } 97 assert!(ROOT.contains("mod publication_attempt;")); 98 assert!(!ROOT.contains("pub mod publication_attempt;")); 99 }