rhi

Coordinated trade for connected markets
git clone https://radroots.dev/git/rhi.git
Log | Files | Refs | README | LICENSE

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 }