myc

Self-custodial remote signer for Radroots apps
git clone https://radroots.dev/git/myc.git
Log | Files | Refs | README | LICENSE

services_hardening_local_signer_transport.rs (6158B)


      1 #![forbid(unsafe_code)]
      2 
      3 use serde_json::json;
      4 
      5 const CONTRACT: &str =
      6     include_str!("../contracts/services_hardening/local_signer_transport.v1.json");
      7 const LIB_SOURCE: &str = include_str!("../src/lib.rs");
      8 const TRANSPORT_SOURCE: &str = include_str!("../src/provider_local_signer.rs");
      9 const PROVIDER_SOURCE: &str = include_str!("../src/provider_contract.rs");
     10 const CARGO_SOURCE: &str = include_str!("../Cargo.toml");
     11 
     12 #[test]
     13 fn machine_contract_freezes_the_complete_local_signer_transport() {
     14     let actual: serde_json::Value = serde_json::from_str(CONTRACT).expect("contract JSON");
     15     assert_eq!(
     16         actual,
     17         json!({
     18             "schema": "radroots.myc.local-signer-transport",
     19             "schema_version": 1,
     20             "contract_version": 1,
     21             "transport": "http_1_1_json_over_unix_domain_socket",
     22             "shared_transport": "radroots_service_host::AdminClient",
     23             "endpoint": "/v1/provider/operation",
     24             "method": "POST",
     25             "outer_admin_contract_version": 1,
     26             "request_fields": [
     27                 "contract_version", "provider_instance", "role", "operation_id",
     28                 "correlation_id", "absolute_deadline_unix_ms", "expected_identity",
     29                 "capability", "input"
     30             ],
     31             "response_fields": [
     32                 "contract_version", "provider_instance", "role", "operation_id",
     33                 "correlation_id", "absolute_deadline_unix_ms", "expected_identity",
     34                 "capability", "result"
     35             ],
     36             "tagged_operations": [
     37                 "describe", "public_identity", "sign_event", "nip04_encrypt",
     38                 "nip04_decrypt", "nip44_encrypt", "nip44_decrypt"
     39             ],
     40             "operation_shapes": {
     41                 "describe": {
     42                     "input_fields": [],
     43                     "result_fields": ["public_identity", "protocol_version", "capabilities", "maximum_request_bytes"]
     44                 },
     45                 "public_identity": {
     46                     "input_fields": [],
     47                     "result_fields": ["public_identity"]
     48                 },
     49                 "sign_event": {
     50                     "input_fields": ["payload_hex"],
     51                     "result_fields": ["payload_hex"]
     52                 },
     53                 "nip04_encrypt": {
     54                     "input_fields": ["peer", "payload_hex"],
     55                     "result_fields": ["peer", "payload_hex"]
     56                 },
     57                 "nip04_decrypt": {
     58                     "input_fields": ["peer", "payload_hex"],
     59                     "result_fields": ["peer", "payload_hex"]
     60                 },
     61                 "nip44_encrypt": {
     62                     "input_fields": ["peer", "version", "payload_hex"],
     63                     "result_fields": ["peer", "version", "payload_hex"]
     64                 },
     65                 "nip44_decrypt": {
     66                     "input_fields": ["peer", "version", "payload_hex"],
     67                     "result_fields": ["peer", "version", "payload_hex"]
     68                 }
     69             },
     70             "protected_payload_encoding": "lowercase_hex",
     71             "limits_source": "validated_provider_binding",
     72             "concurrency_scope": "per_client",
     73             "semantic_success_trusted": false,
     74             "semantic_verification_owner": "step-135",
     75             "cancellation_proves_no_effect": false,
     76             "signing_is_publication": false,
     77             "tcp_allowed": false,
     78             "browser_origin_allowed": false,
     79             "child_process_allowed": false
     80         })
     81     );
     82 }
     83 
     84 #[test]
     85 fn implementation_uses_only_the_hardened_fixed_unix_admin_boundary() {
     86     for required in [
     87         "radroots_service_host = { git = \"https://github.com/radrootslabs/lib\", rev = \"055096853fca95e15d0f813d33a14aca13be3881\"",
     88         "const MYC_LOCAL_SIGNER_ENDPOINT: &str = \"/v1/provider/operation\"",
     89         "radroots_service_host::AdminClient",
     90         ".mutate::<_, LocalSignerResponse>(",
     91         "tokio::sync::Semaphore",
     92         "tokio::time::timeout(self.request_deadline",
     93         "#[serde(tag = \"type\", rename_all = \"snake_case\", deny_unknown_fields)]",
     94         "MycLocalSignerUntrustedResponse",
     95     ] {
     96         assert!(
     97             CARGO_SOURCE.contains(required)
     98                 || TRANSPORT_SOURCE.contains(required)
     99                 || LIB_SOURCE.contains(required),
    100             "missing hardened transport boundary {required}"
    101         );
    102     }
    103     assert!(PROVIDER_SOURCE.contains("pub(crate) fn local_signer_socket_path"));
    104 }
    105 
    106 #[test]
    107 fn no_parallel_transport_provider_execution_or_success_trust_is_introduced() {
    108     let production = TRANSPORT_SOURCE
    109         .split("#[cfg(test)]")
    110         .next()
    111         .expect("production source");
    112     for forbidden in [
    113         "TcpStream",
    114         "reqwest",
    115         "hyper::",
    116         "std::process",
    117         "tokio::process",
    118         "Command::new",
    119         "UnixStream::connect",
    120         "AdminServer",
    121         "signing_is_publication = true",
    122         "semantic_success_trusted = true",
    123         "ServiceSqliteTransaction",
    124     ] {
    125         assert!(
    126             !production.contains(forbidden),
    127             "forbidden local-signer authority {forbidden}"
    128         );
    129     }
    130 }
    131 
    132 #[test]
    133 fn public_boundary_is_sealed_redacted_and_dependency_free() {
    134     for required in [
    135         "pub struct MycLocalSignerClient",
    136         "pub struct MycLocalSignerUntrustedResponse",
    137         "pub enum MycLocalSignerTransportErrorKind",
    138         "pub struct MycLocalSignerTransportError",
    139         "impl Error for MycLocalSignerTransportError {}",
    140         ".field(\"result\", &\"[redacted]\")",
    141     ] {
    142         assert!(TRANSPORT_SOURCE.contains(required));
    143     }
    144     for forbidden in [
    145         "pub transport:",
    146         "pub permits:",
    147         "pub response:",
    148         "pub outer_correlation_id:",
    149         "pub socket_path:",
    150         "pub fn into_inner",
    151         "pub fn raw_response",
    152         "pub source:",
    153         "radroots_service_host::AdminClientError",
    154     ] {
    155         assert!(!LIB_SOURCE.contains(forbidden));
    156     }
    157     assert!(LIB_SOURCE.contains("mod provider_local_signer;"));
    158     assert!(!LIB_SOURCE.contains("pub mod provider_local_signer"));
    159 }