services_hardening_identity_envelope.rs (5042B)
1 #![forbid(unsafe_code)] 2 3 use serde_json::json; 4 5 const CONTRACT: &str = 6 include_str!("../contracts/services_hardening/encrypted_identity_envelope.v1.json"); 7 const ENVELOPE_SOURCE: &str = include_str!("../src/identity_envelope.rs"); 8 const LIB_SOURCE: &str = include_str!("../src/lib.rs"); 9 10 #[test] 11 fn machine_contract_freezes_the_exact_envelope_and_backup_boundary() { 12 let actual: serde_json::Value = serde_json::from_str(CONTRACT).expect("contract JSON"); 13 assert_eq!( 14 actual, 15 json!({ 16 "schema": "radroots.rhi.encrypted-identity-envelope", 17 "schema_version": 1, 18 "contract_version": 1, 19 "radroots_secrets_envelope_version": 2, 20 "encoded_max_bytes": 262144, 21 "identity_secret_bytes": 32, 22 "wrapping_credential_bytes": 32, 23 "provisioning_entropy": { 24 "data_key_bytes": 32, 25 "envelope_nonce_bytes": 24, 26 "wrapping_nonce_bytes": 24, 27 "caller_supplied": true 28 }, 29 "authenticated_context": { 30 "purpose": "radroots.rhi.encrypted_identity", 31 "subject_type": "provider_identity", 32 "subject_value": "service:<expected_public_key>", 33 "payload_schema": "radroots.rhi.identity_secret.v1", 34 "credential_reference_bound": true 35 }, 36 "artifact": { 37 "create_new": true, 38 "overwrite": false, 39 "symlink_follow": false, 40 "regular_file": true, 41 "single_link": true, 42 "owner_uid": "effective_uid", 43 "create_mode_octal": "0600", 44 "read_modes_octal": ["0400", "0600"] 45 }, 46 "verification": { 47 "expected_identity_required": true, 48 "derived_public_key_must_match": true, 49 "legacy_envelope_accepted": false, 50 "ordinary_run_provisions": false 51 }, 52 "backup": { 53 "state_backup_includes_envelope": false, 54 "state_backup_includes_wrapping_credential": false, 55 "state_backup_includes_plaintext_identity": false 56 } 57 }) 58 ); 59 } 60 61 #[test] 62 fn implementation_uses_shared_envelopes_and_seals_credential_resolution() { 63 for required in [ 64 "EncryptedEnvelope::seal(", 65 "EncryptedEnvelope::decode(", 66 ".open(&opener, expected_context)", 67 "binding.role().as_str()", 68 "OFlags::CREATE", 69 "OFlags::EXCL", 70 "OFlags::NOFOLLOW", 71 "Mode::RUSR | Mode::WUSR", 72 "RhiEncryptedIdentityEnvelopeErrorKind::MalformedEnvelope", 73 ] { 74 assert!( 75 ENVELOPE_SOURCE.contains(required), 76 "missing envelope boundary `{required}`" 77 ); 78 } 79 for forbidden in [ 80 "pub fn from_bytes", 81 "pub fn from_resolved_bytes", 82 "std::env::", 83 "process::Command", 84 "keyring::", 85 "LEGACY_ENVELOPE_VERSION", 86 "open_legacy_v1", 87 "reseal_legacy_v1", 88 ".key\"", 89 "create_dir_all", 90 ] { 91 assert!( 92 !ENVELOPE_SOURCE.contains(forbidden), 93 "forbidden envelope authority `{forbidden}`" 94 ); 95 } 96 assert!(LIB_SOURCE.contains("mod identity_envelope;")); 97 assert!(!LIB_SOURCE.contains("pub mod identity_envelope;")); 98 assert!(ENVELOPE_SOURCE.contains("pub(crate) struct RhiCredentialResolutionProof")); 99 assert!(ENVELOPE_SOURCE.contains("pub(crate) fn from_resolution(")); 100 } 101 102 #[test] 103 fn public_models_disclose_no_path_or_secret_escape() { 104 for required in [ 105 "pub struct RhiIdentityEnvelopeBinding", 106 "pub struct RhiWrappingCredential(", 107 "pub struct RhiEncryptedIdentityProvisioningMaterial", 108 "pub struct RhiDecryptedIdentity", 109 "formatter.write_str(\"RhiWrappingCredential([redacted])\")", 110 "Zeroizing<[u8; WRAPPING_CREDENTIAL_BYTES]>", 111 "identity_secret: Zeroizing<[u8; IDENTITY_SECRET_BYTES]>", 112 "impl Error for RhiEncryptedIdentityEnvelopeError {}", 113 ] { 114 assert!( 115 ENVELOPE_SOURCE.contains(required), 116 "missing sealed boundary `{required}`" 117 ); 118 } 119 for forbidden in [ 120 "pub path:", 121 "pub source:", 122 "pub credential:", 123 "pub secret:", 124 "pub data_key:", 125 "pub envelope_nonce:", 126 "pub wrapping_nonce:", 127 "pub fn expose_secret", 128 "pub fn encrypted_envelope_path", 129 ] { 130 assert!(!ENVELOPE_SOURCE.contains(forbidden)); 131 } 132 } 133 134 #[test] 135 fn state_backup_contract_excludes_every_identity_material_class() { 136 let value: serde_json::Value = serde_json::from_str(CONTRACT).expect("contract JSON"); 137 assert_eq!( 138 value["backup"], 139 json!({ 140 "state_backup_includes_envelope": false, 141 "state_backup_includes_wrapping_credential": false, 142 "state_backup_includes_plaintext_identity": false 143 }) 144 ); 145 }