@wlfi-agent/cli 1.4.12 → 1.4.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (289) hide show
  1. package/Cargo.lock +3968 -0
  2. package/Cargo.toml +50 -0
  3. package/README.md +426 -6
  4. package/crates/vault-cli-admin/Cargo.toml +26 -0
  5. package/crates/vault-cli-admin/src/io_utils.rs +500 -0
  6. package/crates/vault-cli-admin/src/main.rs +3990 -0
  7. package/crates/vault-cli-admin/src/shared_config.rs +624 -0
  8. package/crates/vault-cli-admin/src/tui/amounts.rs +180 -0
  9. package/crates/vault-cli-admin/src/tui/token_rpc.rs +250 -0
  10. package/crates/vault-cli-admin/src/tui/utils.rs +82 -0
  11. package/crates/vault-cli-admin/src/tui.rs +3410 -0
  12. package/crates/vault-cli-agent/Cargo.toml +24 -0
  13. package/crates/vault-cli-agent/src/io_utils.rs +576 -0
  14. package/crates/vault-cli-agent/src/main.rs +833 -0
  15. package/crates/vault-cli-daemon/Cargo.toml +28 -0
  16. package/crates/vault-cli-daemon/src/bin/wlfi-agent-system-keychain.rs +216 -0
  17. package/crates/vault-cli-daemon/src/main.rs +644 -0
  18. package/crates/vault-cli-daemon/src/relay_sync.rs +894 -0
  19. package/crates/vault-cli-daemon/tests/system_keychain_helper_acl.rs +167 -0
  20. package/crates/vault-daemon/Cargo.toml +32 -0
  21. package/crates/vault-daemon/src/daemon_parts/api_impl_and_utils.rs +1041 -0
  22. package/crates/vault-daemon/src/daemon_parts/core_helpers.rs +1256 -0
  23. package/crates/vault-daemon/src/daemon_parts/types_api_rpc.rs +622 -0
  24. package/crates/vault-daemon/src/lib.rs +54 -0
  25. package/crates/vault-daemon/src/persistence.rs +441 -0
  26. package/crates/vault-daemon/src/tests.rs +237 -0
  27. package/crates/vault-daemon/src/tests_parts/part1.rs +1224 -0
  28. package/crates/vault-daemon/src/tests_parts/part2.rs +1021 -0
  29. package/crates/vault-daemon/src/tests_parts/part3.rs +835 -0
  30. package/crates/vault-daemon/src/tests_parts/part4.rs +604 -0
  31. package/crates/vault-domain/Cargo.toml +20 -0
  32. package/crates/vault-domain/src/action.rs +849 -0
  33. package/crates/vault-domain/src/address.rs +51 -0
  34. package/crates/vault-domain/src/approval.rs +90 -0
  35. package/crates/vault-domain/src/constants.rs +4 -0
  36. package/crates/vault-domain/src/error.rs +54 -0
  37. package/crates/vault-domain/src/keys.rs +71 -0
  38. package/crates/vault-domain/src/lib.rs +42 -0
  39. package/crates/vault-domain/src/nonce.rs +102 -0
  40. package/crates/vault-domain/src/policy.rs +172 -0
  41. package/crates/vault-domain/src/request.rs +53 -0
  42. package/crates/vault-domain/src/scope.rs +24 -0
  43. package/crates/vault-domain/src/session.rs +50 -0
  44. package/crates/vault-domain/src/signature.rs +34 -0
  45. package/crates/vault-domain/src/tests.rs +651 -0
  46. package/crates/vault-domain/src/u128_as_decimal_string.rs +44 -0
  47. package/crates/vault-policy/Cargo.toml +17 -0
  48. package/crates/vault-policy/src/engine.rs +301 -0
  49. package/crates/vault-policy/src/error.rs +81 -0
  50. package/crates/vault-policy/src/lib.rs +17 -0
  51. package/crates/vault-policy/src/report.rs +34 -0
  52. package/crates/vault-policy/src/tests.rs +891 -0
  53. package/crates/vault-policy/src/tests_explain.rs +78 -0
  54. package/crates/vault-sdk-agent/Cargo.toml +21 -0
  55. package/crates/vault-sdk-agent/src/lib.rs +711 -0
  56. package/crates/vault-signer/Cargo.toml +25 -0
  57. package/crates/vault-signer/src/lib.rs +731 -0
  58. package/crates/vault-signer/tests/secure_enclave_acl.rs +54 -0
  59. package/crates/vault-transport-unix/Cargo.toml +24 -0
  60. package/crates/vault-transport-unix/src/lib.rs +1640 -0
  61. package/crates/vault-transport-xpc/Cargo.toml +25 -0
  62. package/crates/vault-transport-xpc/src/client_codec_api.rs +635 -0
  63. package/crates/vault-transport-xpc/src/lib.rs +680 -0
  64. package/crates/vault-transport-xpc/src/tests.rs +818 -0
  65. package/crates/vault-transport-xpc/tests/e2e_flow.rs +773 -0
  66. package/dist/cli.cjs +35088 -0
  67. package/dist/cli.cjs.map +1 -0
  68. package/package.json +49 -43
  69. package/packages/cache/.turbo/turbo-build.log +52 -0
  70. package/packages/cache/dist/chunk-2QFWMUXT.cjs +43 -0
  71. package/packages/cache/dist/chunk-2QFWMUXT.cjs.map +1 -0
  72. package/packages/cache/dist/chunk-4U63TZTQ.js +43 -0
  73. package/packages/cache/dist/chunk-4U63TZTQ.js.map +1 -0
  74. package/packages/cache/dist/chunk-ALQ6H7KG.cjs +404 -0
  75. package/packages/cache/dist/chunk-ALQ6H7KG.cjs.map +1 -0
  76. package/packages/cache/dist/chunk-FGJEEF5N.js +404 -0
  77. package/packages/cache/dist/chunk-FGJEEF5N.js.map +1 -0
  78. package/packages/cache/dist/chunk-UYNEHZHB.cjs +45 -0
  79. package/packages/cache/dist/chunk-UYNEHZHB.cjs.map +1 -0
  80. package/packages/cache/dist/chunk-VXVMPG3W.js +45 -0
  81. package/packages/cache/dist/chunk-VXVMPG3W.js.map +1 -0
  82. package/packages/cache/dist/client/index.cjs +11 -0
  83. package/packages/cache/dist/client/index.cjs.map +1 -0
  84. package/packages/cache/dist/client/index.d.cts +15 -0
  85. package/packages/cache/dist/client/index.d.ts +15 -0
  86. package/packages/cache/dist/client/index.js +11 -0
  87. package/packages/cache/dist/client/index.js.map +1 -0
  88. package/packages/cache/dist/errors/index.cjs +11 -0
  89. package/packages/cache/dist/errors/index.cjs.map +1 -0
  90. package/packages/cache/dist/errors/index.d.cts +26 -0
  91. package/packages/cache/dist/errors/index.d.ts +26 -0
  92. package/packages/cache/dist/errors/index.js +11 -0
  93. package/packages/cache/dist/errors/index.js.map +1 -0
  94. package/packages/cache/dist/index.cjs +29 -0
  95. package/packages/cache/dist/index.cjs.map +1 -0
  96. package/packages/cache/dist/index.d.cts +4 -0
  97. package/packages/cache/dist/index.d.ts +4 -0
  98. package/packages/cache/dist/index.js +29 -0
  99. package/packages/cache/dist/index.js.map +1 -0
  100. package/packages/cache/dist/service/index.cjs +15 -0
  101. package/packages/cache/dist/service/index.cjs.map +1 -0
  102. package/packages/cache/dist/service/index.d.cts +184 -0
  103. package/packages/cache/dist/service/index.d.ts +184 -0
  104. package/packages/cache/dist/service/index.js +15 -0
  105. package/packages/cache/dist/service/index.js.map +1 -0
  106. package/packages/cache/node_modules/.bin/jiti +17 -0
  107. package/packages/cache/node_modules/.bin/tsc +17 -0
  108. package/packages/cache/node_modules/.bin/tsserver +17 -0
  109. package/packages/cache/node_modules/.bin/tsup +17 -0
  110. package/packages/cache/node_modules/.bin/tsup-node +17 -0
  111. package/packages/cache/node_modules/.bin/tsx +17 -0
  112. package/packages/cache/node_modules/.bin/vitest +17 -0
  113. package/packages/cache/package.json +48 -0
  114. package/packages/cache/src/client/index.ts +56 -0
  115. package/packages/cache/src/errors/index.ts +53 -0
  116. package/packages/cache/src/index.ts +3 -0
  117. package/packages/cache/src/service/index.test.ts +263 -0
  118. package/packages/cache/src/service/index.ts +678 -0
  119. package/packages/cache/tsconfig.json +13 -0
  120. package/packages/cache/tsup.config.ts +13 -0
  121. package/packages/cache/vitest.config.ts +16 -0
  122. package/packages/config/.turbo/turbo-build.log +18 -0
  123. package/packages/config/dist/index.cjs +1037 -0
  124. package/packages/config/dist/index.cjs.map +1 -0
  125. package/packages/config/dist/index.d.ts +131 -0
  126. package/packages/config/node_modules/.bin/jiti +17 -0
  127. package/packages/config/node_modules/.bin/tsc +17 -0
  128. package/packages/config/node_modules/.bin/tsserver +17 -0
  129. package/packages/config/node_modules/.bin/tsup +17 -0
  130. package/packages/config/node_modules/.bin/tsup-node +17 -0
  131. package/packages/config/node_modules/.bin/tsx +17 -0
  132. package/packages/config/package.json +21 -0
  133. package/packages/config/src/index.js +1 -0
  134. package/packages/config/src/index.ts +1282 -0
  135. package/packages/config/tsconfig.json +4 -0
  136. package/packages/rpc/.turbo/turbo-build.log +32 -0
  137. package/packages/rpc/dist/_esm-BCLXDO2R.cjs +3660 -0
  138. package/packages/rpc/dist/_esm-BCLXDO2R.cjs.map +1 -0
  139. package/packages/rpc/dist/ccip-OWJLAW55.cjs +16 -0
  140. package/packages/rpc/dist/ccip-OWJLAW55.cjs.map +1 -0
  141. package/packages/rpc/dist/chunk-APQIFZ3B.cjs +6247 -0
  142. package/packages/rpc/dist/chunk-APQIFZ3B.cjs.map +1 -0
  143. package/packages/rpc/dist/chunk-CDO2GWRD.cjs +410 -0
  144. package/packages/rpc/dist/chunk-CDO2GWRD.cjs.map +1 -0
  145. package/packages/rpc/dist/chunk-QGTNTFJ7.cjs +2249 -0
  146. package/packages/rpc/dist/chunk-QGTNTFJ7.cjs.map +1 -0
  147. package/packages/rpc/dist/chunk-TZDTAHWR.cjs +44 -0
  148. package/packages/rpc/dist/chunk-TZDTAHWR.cjs.map +1 -0
  149. package/packages/rpc/dist/index.cjs +7342 -0
  150. package/packages/rpc/dist/index.cjs.map +1 -0
  151. package/packages/rpc/dist/index.d.ts +3857 -0
  152. package/packages/rpc/dist/secp256k1-WCNM675D.cjs +18 -0
  153. package/packages/rpc/dist/secp256k1-WCNM675D.cjs.map +1 -0
  154. package/packages/rpc/node_modules/.bin/jiti +17 -0
  155. package/packages/rpc/node_modules/.bin/tsc +17 -0
  156. package/packages/rpc/node_modules/.bin/tsserver +17 -0
  157. package/packages/rpc/node_modules/.bin/tsup +17 -0
  158. package/packages/rpc/node_modules/.bin/tsup-node +17 -0
  159. package/packages/rpc/node_modules/.bin/tsx +17 -0
  160. package/packages/rpc/package.json +25 -0
  161. package/packages/rpc/src/index.ts +206 -0
  162. package/packages/rpc/tsconfig.json +4 -0
  163. package/packages/typescript/base.json +36 -0
  164. package/packages/typescript/nextjs.json +17 -0
  165. package/packages/typescript/package.json +10 -0
  166. package/packages/ui/.turbo/turbo-build.log +44 -0
  167. package/packages/ui/dist/chunk-MOAFBKSA.js +11 -0
  168. package/packages/ui/dist/chunk-MOAFBKSA.js.map +1 -0
  169. package/packages/ui/dist/components/badge.d.ts +12 -0
  170. package/packages/ui/dist/components/badge.js +31 -0
  171. package/packages/ui/dist/components/badge.js.map +1 -0
  172. package/packages/ui/dist/components/button.d.ts +13 -0
  173. package/packages/ui/dist/components/button.js +40 -0
  174. package/packages/ui/dist/components/button.js.map +1 -0
  175. package/packages/ui/dist/components/card.d.ts +10 -0
  176. package/packages/ui/dist/components/card.js +39 -0
  177. package/packages/ui/dist/components/card.js.map +1 -0
  178. package/packages/ui/dist/components/input.d.ts +5 -0
  179. package/packages/ui/dist/components/input.js +28 -0
  180. package/packages/ui/dist/components/input.js.map +1 -0
  181. package/packages/ui/dist/components/label.d.ts +5 -0
  182. package/packages/ui/dist/components/label.js +13 -0
  183. package/packages/ui/dist/components/label.js.map +1 -0
  184. package/packages/ui/dist/components/separator.d.ts +5 -0
  185. package/packages/ui/dist/components/separator.js +13 -0
  186. package/packages/ui/dist/components/separator.js.map +1 -0
  187. package/packages/ui/dist/components/textarea.d.ts +5 -0
  188. package/packages/ui/dist/components/textarea.js +27 -0
  189. package/packages/ui/dist/components/textarea.js.map +1 -0
  190. package/packages/ui/dist/tailwind.d.ts +56 -0
  191. package/packages/ui/dist/tailwind.js +60 -0
  192. package/packages/ui/dist/tailwind.js.map +1 -0
  193. package/packages/ui/dist/utils/cn.d.ts +5 -0
  194. package/packages/ui/dist/utils/cn.js +7 -0
  195. package/packages/ui/dist/utils/cn.js.map +1 -0
  196. package/packages/ui/node_modules/.bin/jiti +17 -0
  197. package/packages/ui/node_modules/.bin/tsc +17 -0
  198. package/packages/ui/node_modules/.bin/tsserver +17 -0
  199. package/packages/ui/node_modules/.bin/tsup +17 -0
  200. package/packages/ui/node_modules/.bin/tsup-node +17 -0
  201. package/packages/ui/node_modules/.bin/tsx +17 -0
  202. package/packages/ui/package.json +69 -0
  203. package/packages/ui/src/components/badge.tsx +27 -0
  204. package/packages/ui/src/components/button.tsx +40 -0
  205. package/packages/ui/src/components/card.tsx +31 -0
  206. package/packages/ui/src/components/input.tsx +21 -0
  207. package/packages/ui/src/components/label.tsx +6 -0
  208. package/packages/ui/src/components/separator.tsx +6 -0
  209. package/packages/ui/src/components/textarea.tsx +20 -0
  210. package/packages/ui/src/globals.css +70 -0
  211. package/packages/ui/src/tailwind.ts +56 -0
  212. package/packages/ui/src/utils/cn.ts +6 -0
  213. package/packages/ui/tsconfig.json +20 -0
  214. package/packages/ui/tsup.config.ts +20 -0
  215. package/pnpm-workspace.yaml +4 -0
  216. package/scripts/install-rust-binaries.mjs +84 -0
  217. package/scripts/launchd/install-user-daemon.sh +358 -0
  218. package/scripts/launchd/run-vault-daemon.sh +5 -0
  219. package/scripts/launchd/run-wlfi-agent-daemon.sh +73 -0
  220. package/scripts/launchd/uninstall-user-daemon.sh +103 -0
  221. package/src/cli.ts +2121 -0
  222. package/src/lib/admin-guard.js +1 -0
  223. package/src/lib/admin-guard.ts +185 -0
  224. package/src/lib/admin-passthrough.ts +33 -0
  225. package/src/lib/admin-reset.ts +751 -0
  226. package/src/lib/admin-setup.ts +1612 -0
  227. package/src/lib/agent-auth-clear.js +1 -0
  228. package/src/lib/agent-auth-clear.ts +58 -0
  229. package/src/lib/agent-auth-forwarding.js +1 -0
  230. package/src/lib/agent-auth-forwarding.ts +149 -0
  231. package/src/lib/agent-auth-migrate.js +1 -0
  232. package/src/lib/agent-auth-migrate.ts +150 -0
  233. package/src/lib/agent-auth-revoke.ts +103 -0
  234. package/src/lib/agent-auth-rotate.ts +107 -0
  235. package/src/lib/agent-auth-token.js +1 -0
  236. package/src/lib/agent-auth-token.ts +25 -0
  237. package/src/lib/agent-auth.ts +89 -0
  238. package/src/lib/asset-broadcast.js +1 -0
  239. package/src/lib/asset-broadcast.ts +285 -0
  240. package/src/lib/bootstrap-artifacts.js +1 -0
  241. package/src/lib/bootstrap-artifacts.ts +205 -0
  242. package/src/lib/bootstrap-credentials.js +1 -0
  243. package/src/lib/bootstrap-credentials.ts +832 -0
  244. package/src/lib/config-amounts.js +1 -0
  245. package/src/lib/config-amounts.ts +189 -0
  246. package/src/lib/config-mutation.ts +27 -0
  247. package/src/lib/fs-trust.js +1 -0
  248. package/src/lib/fs-trust.ts +537 -0
  249. package/src/lib/keychain.js +1 -0
  250. package/src/lib/keychain.ts +225 -0
  251. package/src/lib/local-admin-access.ts +106 -0
  252. package/src/lib/network-selection.js +1 -0
  253. package/src/lib/network-selection.ts +71 -0
  254. package/src/lib/passthrough-security.js +1 -0
  255. package/src/lib/passthrough-security.ts +114 -0
  256. package/src/lib/rpc-guard.js +1 -0
  257. package/src/lib/rpc-guard.ts +7 -0
  258. package/src/lib/rust-spawn-options.js +1 -0
  259. package/src/lib/rust-spawn-options.ts +98 -0
  260. package/src/lib/rust.js +1 -0
  261. package/src/lib/rust.ts +143 -0
  262. package/src/lib/signed-tx.js +1 -0
  263. package/src/lib/signed-tx.ts +116 -0
  264. package/src/lib/status-repair-cli.ts +116 -0
  265. package/src/lib/sudo.js +1 -0
  266. package/src/lib/sudo.ts +172 -0
  267. package/src/lib/vault-password-forwarding.js +1 -0
  268. package/src/lib/vault-password-forwarding.ts +155 -0
  269. package/src/lib/wallet-profile.js +1 -0
  270. package/src/lib/wallet-profile.ts +332 -0
  271. package/src/lib/wallet-repair.js +1 -0
  272. package/src/lib/wallet-repair.ts +304 -0
  273. package/src/lib/wallet-setup.js +1 -0
  274. package/src/lib/wallet-setup.ts +1466 -0
  275. package/src/lib/wallet-status.js +1 -0
  276. package/src/lib/wallet-status.ts +640 -0
  277. package/tsconfig.base.json +17 -0
  278. package/tsconfig.json +10 -0
  279. package/tsup.config.ts +25 -0
  280. package/turbo.json +41 -0
  281. package/LICENSE.md +0 -1
  282. package/dist/wlfa/index.cjs +0 -250
  283. package/dist/wlfa/index.d.cts +0 -1
  284. package/dist/wlfa/index.d.ts +0 -1
  285. package/dist/wlfa/index.js +0 -250
  286. package/dist/wlfc/index.cjs +0 -1894
  287. package/dist/wlfc/index.d.cts +0 -1
  288. package/dist/wlfc/index.d.ts +0 -1
  289. package/dist/wlfc/index.js +0 -1894
@@ -0,0 +1,680 @@
1
+ //! XPC transport adapter for daemon RPC calls.
2
+ //!
3
+ //! This crate uses Apple XPC primitives to exchange typed daemon RPC messages
4
+ //! between a server and a client.
5
+
6
+ use std::collections::HashMap;
7
+ use std::ffi::{CStr, CString};
8
+ use std::fmt;
9
+ use std::os::raw::{c_char, c_void};
10
+ use std::ptr;
11
+ use std::sync::mpsc::{self, Receiver};
12
+ use std::sync::{Arc, Mutex};
13
+ use std::time::Duration;
14
+
15
+ use async_trait::async_trait;
16
+ use serde::{Deserialize, Serialize};
17
+ use thiserror::Error;
18
+ use tokio::runtime::Handle;
19
+ use uuid::Uuid;
20
+ use vault_daemon::{
21
+ DaemonError, DaemonRpcRequest, DaemonRpcResponse, InMemoryDaemon, KeyManagerDaemonApi,
22
+ };
23
+ use vault_domain::{
24
+ AdminSession, AgentCredentials, Lease, ManualApprovalDecision, ManualApprovalRequest,
25
+ NonceReleaseRequest, NonceReservation, NonceReservationRequest, PolicyAttachment, RelayConfig,
26
+ SignRequest, Signature, SpendingPolicy, VaultKey,
27
+ };
28
+ use vault_policy::{PolicyError, PolicyEvaluation, PolicyExplanation};
29
+ use vault_signer::{KeyCreateRequest, SignerError, VaultSignerBackend};
30
+ use zeroize::Zeroize;
31
+
32
+ #[cfg(target_os = "macos")]
33
+ use block::{Block, ConcreteBlock, RcBlock};
34
+ #[cfg(target_os = "macos")]
35
+ use security_framework::os::macos::code_signing::{
36
+ Flags as CodeSignFlags, GuestAttributes, SecCode, SecRequirement,
37
+ };
38
+
39
+ #[cfg(target_os = "macos")]
40
+ type XpcObject = *mut c_void;
41
+ #[cfg(target_os = "macos")]
42
+ type XpcConnection = *mut c_void;
43
+ #[cfg(target_os = "macos")]
44
+ type DispatchQueue = *mut c_void;
45
+ #[cfg(target_os = "macos")]
46
+ type XpcType = *const c_void;
47
+ #[cfg(target_os = "macos")]
48
+ type PeerBlocks = Arc<Mutex<HashMap<usize, SendablePeerBlock>>>;
49
+
50
+ #[cfg(target_os = "macos")]
51
+ const DISPATCH_QUEUE_PRIORITY_DEFAULT: isize = 0;
52
+
53
+ /// Wrapper for copied peer callback blocks stored by the server.
54
+ ///
55
+ /// The underlying copied Objective-C block is heap-managed by Apple runtime and
56
+ /// can be retained/released across threads. Access to the map is synchronized by
57
+ /// a mutex, and blocks are only invoked by XPC runtime callbacks.
58
+ #[cfg(target_os = "macos")]
59
+ struct SendablePeerBlock {
60
+ _block: RcBlock<(XpcObject,), ()>,
61
+ }
62
+
63
+ // SAFETY: copied Objective-C blocks are reference-counted runtime objects that
64
+ // are designed for cross-thread ownership transfer.
65
+ #[cfg(target_os = "macos")]
66
+ unsafe impl Send for SendablePeerBlock {}
67
+ // SAFETY: all shared access is mediated by synchronization on the block map.
68
+ #[cfg(target_os = "macos")]
69
+ unsafe impl Sync for SendablePeerBlock {}
70
+
71
+ #[cfg(target_os = "macos")]
72
+ unsafe extern "C" {
73
+ fn xpc_connection_create(name: *const c_char, target_queue: DispatchQueue) -> XpcConnection;
74
+ fn xpc_connection_create_from_endpoint(endpoint: XpcObject) -> XpcConnection;
75
+ fn xpc_endpoint_create(connection: XpcConnection) -> XpcObject;
76
+
77
+ fn xpc_connection_set_event_handler(connection: XpcConnection, handler: *mut c_void);
78
+ fn xpc_connection_resume(connection: XpcConnection);
79
+ fn xpc_connection_cancel(connection: XpcConnection);
80
+ fn xpc_connection_send_message(connection: XpcConnection, message: XpcObject);
81
+ fn xpc_connection_get_euid(connection: XpcConnection) -> libc::uid_t;
82
+ fn xpc_connection_get_pid(connection: XpcConnection) -> libc::pid_t;
83
+
84
+ fn xpc_dictionary_create(
85
+ keys: *const *const c_char,
86
+ values: *const XpcObject,
87
+ count: usize,
88
+ ) -> XpcObject;
89
+ fn xpc_dictionary_set_string(dict: XpcObject, key: *const c_char, value: *const c_char);
90
+ fn xpc_dictionary_set_bool(dict: XpcObject, key: *const c_char, value: bool);
91
+ fn xpc_dictionary_get_string(dict: XpcObject, key: *const c_char) -> *const c_char;
92
+ fn xpc_dictionary_get_bool(dict: XpcObject, key: *const c_char) -> bool;
93
+
94
+ fn xpc_get_type(object: XpcObject) -> XpcType;
95
+
96
+ fn xpc_retain(object: XpcObject) -> XpcObject;
97
+ fn xpc_release(object: XpcObject);
98
+
99
+ static _xpc_type_dictionary: c_void;
100
+ static _xpc_type_connection: c_void;
101
+ }
102
+
103
+ #[cfg(target_os = "macos")]
104
+ #[link(name = "System", kind = "dylib")]
105
+ unsafe extern "C" {
106
+ fn dispatch_get_global_queue(identifier: isize, flags: usize) -> DispatchQueue;
107
+ }
108
+
109
+ /// Errors returned by XPC transport.
110
+ #[derive(Debug, Error)]
111
+ pub enum XpcTransportError {
112
+ /// XPC is unavailable on this platform.
113
+ #[error("xpc transport is supported only on macOS")]
114
+ UnsupportedPlatform,
115
+ /// Message serialization or deserialization failed.
116
+ #[error("serialization error: {0}")]
117
+ Serialization(String),
118
+ /// Protocol-level violation.
119
+ #[error("protocol error: {0}")]
120
+ Protocol(String),
121
+ /// Underlying daemon returned an error.
122
+ #[error("daemon error: {0}")]
123
+ Daemon(#[from] DaemonError),
124
+ /// Timed out waiting for response.
125
+ #[error("timed out waiting for xpc response")]
126
+ Timeout,
127
+ /// Daemon server must run as root for hardened local-access boundary.
128
+ #[error("xpc daemon server must run as root (euid 0)")]
129
+ RequiresRoot,
130
+ /// Code-signing policy was invalid or client failed requirement checks.
131
+ #[error("code-signing authorization error: {0}")]
132
+ CodeSigning(String),
133
+ /// Other transport failures.
134
+ #[error("transport internal error: {0}")]
135
+ Internal(String),
136
+ }
137
+
138
+ #[derive(Debug, Clone, Serialize, Deserialize)]
139
+ struct WireRequest {
140
+ request_id: String,
141
+ body_json: String,
142
+ }
143
+
144
+ #[derive(Debug, Clone, Serialize, Deserialize)]
145
+ struct WireResponse {
146
+ request_id: String,
147
+ ok: bool,
148
+ body_json: String,
149
+ }
150
+
151
+ #[cfg(target_os = "macos")]
152
+ #[derive(Debug)]
153
+ enum IncomingWireMessage {
154
+ Response(WireResponse),
155
+ DecodeError(XpcTransportError),
156
+ }
157
+
158
+ const MAX_WIRE_BODY_BYTES: usize = 256 * 1024;
159
+ const MAX_WIRE_REQUEST_ID_BYTES: usize = 128;
160
+
161
+ #[derive(Debug, Clone, Serialize, Deserialize)]
162
+ #[serde(tag = "kind", content = "data")]
163
+ enum WireDaemonError {
164
+ AuthenticationFailed,
165
+ UnknownLease,
166
+ InvalidLease,
167
+ TooManyActiveLeases,
168
+ UnknownVaultKey(Uuid),
169
+ UnknownAgentKey(Uuid),
170
+ UnknownPolicy(Uuid),
171
+ UnknownManualApprovalRequest(Uuid),
172
+ AgentAuthenticationFailed,
173
+ PayloadActionMismatch,
174
+ PayloadTooLarge {
175
+ max_bytes: usize,
176
+ },
177
+ InvalidRequestTimestamps,
178
+ RequestExpired,
179
+ RequestReplayDetected,
180
+ InvalidPolicyAttachment(String),
181
+ InvalidNonceReservation(String),
182
+ UnknownNonceReservation(Uuid),
183
+ MissingNonceReservation {
184
+ chain_id: u64,
185
+ nonce: u64,
186
+ },
187
+ InvalidPolicy(String),
188
+ InvalidRelayConfig(String),
189
+ ManualApprovalRequired {
190
+ approval_request_id: Uuid,
191
+ relay_url: Option<String>,
192
+ frontend_url: Option<String>,
193
+ },
194
+ ManualApprovalRejected {
195
+ approval_request_id: Uuid,
196
+ },
197
+ Policy(PolicyError),
198
+ Signer(SignerError),
199
+ PasswordHash(String),
200
+ InvalidConfig(String),
201
+ LockPoisoned,
202
+ Transport(String),
203
+ Persistence(String),
204
+ }
205
+
206
+ impl From<DaemonError> for WireDaemonError {
207
+ fn from(value: DaemonError) -> Self {
208
+ match value {
209
+ DaemonError::AuthenticationFailed => Self::AuthenticationFailed,
210
+ DaemonError::UnknownLease => Self::UnknownLease,
211
+ DaemonError::InvalidLease => Self::InvalidLease,
212
+ DaemonError::TooManyActiveLeases => Self::TooManyActiveLeases,
213
+ DaemonError::UnknownVaultKey(id) => Self::UnknownVaultKey(id),
214
+ DaemonError::UnknownAgentKey(id) => Self::UnknownAgentKey(id),
215
+ DaemonError::UnknownPolicy(id) => Self::UnknownPolicy(id),
216
+ DaemonError::UnknownManualApprovalRequest(id) => Self::UnknownManualApprovalRequest(id),
217
+ DaemonError::AgentAuthenticationFailed => Self::AgentAuthenticationFailed,
218
+ DaemonError::PayloadActionMismatch => Self::PayloadActionMismatch,
219
+ DaemonError::PayloadTooLarge { max_bytes } => Self::PayloadTooLarge { max_bytes },
220
+ DaemonError::InvalidRequestTimestamps => Self::InvalidRequestTimestamps,
221
+ DaemonError::RequestExpired => Self::RequestExpired,
222
+ DaemonError::RequestReplayDetected => Self::RequestReplayDetected,
223
+ DaemonError::InvalidPolicyAttachment(msg) => Self::InvalidPolicyAttachment(msg),
224
+ DaemonError::InvalidNonceReservation(msg) => Self::InvalidNonceReservation(msg),
225
+ DaemonError::UnknownNonceReservation(id) => Self::UnknownNonceReservation(id),
226
+ DaemonError::MissingNonceReservation { chain_id, nonce } => {
227
+ Self::MissingNonceReservation { chain_id, nonce }
228
+ }
229
+ DaemonError::InvalidPolicy(msg) => Self::InvalidPolicy(msg),
230
+ DaemonError::InvalidRelayConfig(msg) => Self::InvalidRelayConfig(msg),
231
+ DaemonError::ManualApprovalRequired {
232
+ approval_request_id,
233
+ relay_url,
234
+ frontend_url,
235
+ } => Self::ManualApprovalRequired {
236
+ approval_request_id,
237
+ relay_url,
238
+ frontend_url,
239
+ },
240
+ DaemonError::ManualApprovalRejected {
241
+ approval_request_id,
242
+ } => Self::ManualApprovalRejected {
243
+ approval_request_id,
244
+ },
245
+ DaemonError::Policy(err) => Self::Policy(err),
246
+ DaemonError::Signer(err) => Self::Signer(err),
247
+ DaemonError::PasswordHash(msg) => Self::PasswordHash(msg),
248
+ DaemonError::InvalidConfig(msg) => Self::InvalidConfig(msg),
249
+ DaemonError::LockPoisoned => Self::LockPoisoned,
250
+ DaemonError::Transport(msg) => Self::Transport(msg),
251
+ DaemonError::Persistence(msg) => Self::Persistence(msg),
252
+ }
253
+ }
254
+ }
255
+
256
+ impl WireDaemonError {
257
+ fn into_daemon_error(self) -> DaemonError {
258
+ match self {
259
+ WireDaemonError::AuthenticationFailed => DaemonError::AuthenticationFailed,
260
+ WireDaemonError::UnknownLease => DaemonError::UnknownLease,
261
+ WireDaemonError::InvalidLease => DaemonError::InvalidLease,
262
+ WireDaemonError::TooManyActiveLeases => DaemonError::TooManyActiveLeases,
263
+ WireDaemonError::UnknownVaultKey(id) => DaemonError::UnknownVaultKey(id),
264
+ WireDaemonError::UnknownAgentKey(id) => DaemonError::UnknownAgentKey(id),
265
+ WireDaemonError::UnknownPolicy(id) => DaemonError::UnknownPolicy(id),
266
+ WireDaemonError::UnknownManualApprovalRequest(id) => {
267
+ DaemonError::UnknownManualApprovalRequest(id)
268
+ }
269
+ WireDaemonError::AgentAuthenticationFailed => DaemonError::AgentAuthenticationFailed,
270
+ WireDaemonError::PayloadActionMismatch => DaemonError::PayloadActionMismatch,
271
+ WireDaemonError::PayloadTooLarge { max_bytes } => {
272
+ DaemonError::PayloadTooLarge { max_bytes }
273
+ }
274
+ WireDaemonError::InvalidRequestTimestamps => DaemonError::InvalidRequestTimestamps,
275
+ WireDaemonError::RequestExpired => DaemonError::RequestExpired,
276
+ WireDaemonError::RequestReplayDetected => DaemonError::RequestReplayDetected,
277
+ WireDaemonError::InvalidPolicyAttachment(msg) => {
278
+ DaemonError::InvalidPolicyAttachment(msg)
279
+ }
280
+ WireDaemonError::InvalidNonceReservation(msg) => {
281
+ DaemonError::InvalidNonceReservation(msg)
282
+ }
283
+ WireDaemonError::UnknownNonceReservation(id) => {
284
+ DaemonError::UnknownNonceReservation(id)
285
+ }
286
+ WireDaemonError::MissingNonceReservation { chain_id, nonce } => {
287
+ DaemonError::MissingNonceReservation { chain_id, nonce }
288
+ }
289
+ WireDaemonError::InvalidPolicy(msg) => DaemonError::InvalidPolicy(msg),
290
+ WireDaemonError::InvalidRelayConfig(msg) => DaemonError::InvalidRelayConfig(msg),
291
+ WireDaemonError::ManualApprovalRequired {
292
+ approval_request_id,
293
+ relay_url,
294
+ frontend_url,
295
+ } => DaemonError::ManualApprovalRequired {
296
+ approval_request_id,
297
+ relay_url,
298
+ frontend_url,
299
+ },
300
+ WireDaemonError::ManualApprovalRejected {
301
+ approval_request_id,
302
+ } => DaemonError::ManualApprovalRejected {
303
+ approval_request_id,
304
+ },
305
+ WireDaemonError::Policy(err) => DaemonError::Policy(err),
306
+ WireDaemonError::Signer(err) => DaemonError::Signer(err),
307
+ WireDaemonError::PasswordHash(msg) => DaemonError::PasswordHash(msg),
308
+ WireDaemonError::InvalidConfig(msg) => DaemonError::InvalidConfig(msg),
309
+ WireDaemonError::LockPoisoned => DaemonError::LockPoisoned,
310
+ WireDaemonError::Transport(msg) => DaemonError::Transport(msg),
311
+ WireDaemonError::Persistence(msg) => DaemonError::Persistence(msg),
312
+ }
313
+ }
314
+ }
315
+
316
+ /// Opaque endpoint handle used to connect XPC clients.
317
+ #[cfg(target_os = "macos")]
318
+ pub struct XpcEndpoint {
319
+ raw: XpcObject,
320
+ }
321
+
322
+ #[cfg(target_os = "macos")]
323
+ impl Clone for XpcEndpoint {
324
+ fn clone(&self) -> Self {
325
+ // SAFETY: balanced retain/release lifecycle.
326
+ unsafe {
327
+ xpc_retain(self.raw);
328
+ }
329
+ Self { raw: self.raw }
330
+ }
331
+ }
332
+
333
+ #[cfg(target_os = "macos")]
334
+ impl Drop for XpcEndpoint {
335
+ fn drop(&mut self) {
336
+ // SAFETY: balanced retain/release lifecycle.
337
+ unsafe {
338
+ xpc_release(self.raw);
339
+ }
340
+ }
341
+ }
342
+
343
+ #[cfg(target_os = "macos")]
344
+ impl fmt::Debug for XpcEndpoint {
345
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
346
+ f.debug_struct("XpcEndpoint").finish_non_exhaustive()
347
+ }
348
+ }
349
+
350
+ /// XPC server bound to an in-memory daemon instance.
351
+ #[cfg(target_os = "macos")]
352
+ pub struct XpcDaemonServer {
353
+ listener: XpcConnection,
354
+ endpoint: XpcEndpoint,
355
+ _listener_block: RcBlock<(XpcObject,), ()>,
356
+ _peer_blocks: PeerBlocks,
357
+ }
358
+
359
+ #[cfg(target_os = "macos")]
360
+ impl Drop for XpcDaemonServer {
361
+ fn drop(&mut self) {
362
+ // SAFETY: listener is owned by this instance.
363
+ unsafe {
364
+ xpc_release(self.listener);
365
+ }
366
+ }
367
+ }
368
+
369
+ #[cfg(target_os = "macos")]
370
+ impl XpcDaemonServer {
371
+ /// Starts an anonymous XPC listener and binds it to daemon RPC handler.
372
+ pub fn start_inmemory<B>(
373
+ daemon: Arc<InMemoryDaemon<B>>,
374
+ runtime_handle: Handle,
375
+ ) -> Result<Self, XpcTransportError>
376
+ where
377
+ B: VaultSignerBackend + 'static,
378
+ {
379
+ let current_euid = unsafe { libc::geteuid() };
380
+ if current_euid != 0 {
381
+ return Err(XpcTransportError::RequiresRoot);
382
+ }
383
+
384
+ Self::start_inmemory_impl(daemon, runtime_handle, 0, None)
385
+ }
386
+
387
+ /// Starts an anonymous XPC listener and enforces a code-sign requirement
388
+ /// string on each connecting client process.
389
+ ///
390
+ /// The requirement string uses Apple's requirement language (same syntax as
391
+ /// `codesign -r`).
392
+ pub fn start_inmemory_with_code_sign_requirement<B>(
393
+ daemon: Arc<InMemoryDaemon<B>>,
394
+ runtime_handle: Handle,
395
+ required_client_code_signing_requirement: impl Into<String>,
396
+ ) -> Result<Self, XpcTransportError>
397
+ where
398
+ B: VaultSignerBackend + 'static,
399
+ {
400
+ let current_euid = unsafe { libc::geteuid() };
401
+ if current_euid != 0 {
402
+ return Err(XpcTransportError::RequiresRoot);
403
+ }
404
+
405
+ Self::start_inmemory_impl(
406
+ daemon,
407
+ runtime_handle,
408
+ 0,
409
+ Some(required_client_code_signing_requirement.into()),
410
+ )
411
+ }
412
+
413
+ /// Starts an anonymous XPC listener and restricts clients to `allowed_euid`.
414
+ ///
415
+ /// This is intended for controlled test/dev environments and is only
416
+ /// available in debug builds. Production should use [`Self::start_inmemory`]
417
+ /// so non-root startup is rejected.
418
+ #[cfg(debug_assertions)]
419
+ pub fn start_inmemory_with_allowed_euid<B>(
420
+ daemon: Arc<InMemoryDaemon<B>>,
421
+ runtime_handle: Handle,
422
+ allowed_euid: libc::uid_t,
423
+ ) -> Result<Self, XpcTransportError>
424
+ where
425
+ B: VaultSignerBackend + 'static,
426
+ {
427
+ Self::start_inmemory_impl(daemon, runtime_handle, allowed_euid, None)
428
+ }
429
+
430
+ /// Starts an anonymous XPC listener, restricting clients to `allowed_euid`
431
+ /// and a code-sign requirement.
432
+ #[cfg(debug_assertions)]
433
+ pub fn start_inmemory_with_allowed_euid_and_code_sign_requirement<B>(
434
+ daemon: Arc<InMemoryDaemon<B>>,
435
+ runtime_handle: Handle,
436
+ allowed_euid: libc::uid_t,
437
+ required_client_code_signing_requirement: impl Into<String>,
438
+ ) -> Result<Self, XpcTransportError>
439
+ where
440
+ B: VaultSignerBackend + 'static,
441
+ {
442
+ Self::start_inmemory_impl(
443
+ daemon,
444
+ runtime_handle,
445
+ allowed_euid,
446
+ Some(required_client_code_signing_requirement.into()),
447
+ )
448
+ }
449
+
450
+ fn start_inmemory_impl<B>(
451
+ daemon: Arc<InMemoryDaemon<B>>,
452
+ runtime_handle: Handle,
453
+ allowed_euid: libc::uid_t,
454
+ required_client_code_signing_requirement: Option<String>,
455
+ ) -> Result<Self, XpcTransportError>
456
+ where
457
+ B: VaultSignerBackend + 'static,
458
+ {
459
+ let current_euid = unsafe { libc::geteuid() };
460
+ if allowed_euid != current_euid {
461
+ return Err(XpcTransportError::Internal(format!(
462
+ "allowed_euid mismatch: requested {allowed_euid}, current daemon euid is {current_euid}"
463
+ )));
464
+ }
465
+
466
+ if let Some(requirement) = required_client_code_signing_requirement.as_deref() {
467
+ parse_code_sign_requirement(requirement)?;
468
+ }
469
+
470
+ // SAFETY: XPC/libdispatch APIs are FFI and require raw pointers.
471
+ unsafe {
472
+ let queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
473
+ if queue.is_null() {
474
+ return Err(XpcTransportError::Internal(
475
+ "dispatch_get_global_queue returned null".to_string(),
476
+ ));
477
+ }
478
+
479
+ let listener = xpc_connection_create(ptr::null(), queue);
480
+ if listener.is_null() {
481
+ return Err(XpcTransportError::Internal(
482
+ "xpc_connection_create returned null".to_string(),
483
+ ));
484
+ }
485
+
486
+ let daemon_outer = daemon.clone();
487
+ let handle_outer = runtime_handle.clone();
488
+ let required_client_code_signing_requirement_outer =
489
+ required_client_code_signing_requirement.clone();
490
+ let peer_blocks: PeerBlocks = Arc::new(Mutex::new(HashMap::new()));
491
+ let peer_blocks_for_listener = peer_blocks.clone();
492
+ let listener_block = ConcreteBlock::new(move |event: XpcObject| {
493
+ // Listener callback receives peer connections.
494
+ if !ptr::eq(xpc_get_type(event), &_xpc_type_connection) {
495
+ return;
496
+ }
497
+ let peer = event;
498
+ let peer_euid = xpc_connection_get_euid(peer);
499
+ if peer_euid != allowed_euid {
500
+ xpc_connection_cancel(peer);
501
+ return;
502
+ }
503
+ if let Some(requirement) = required_client_code_signing_requirement_outer.as_deref()
504
+ {
505
+ if verify_peer_code_signing_requirement(peer, requirement).is_err() {
506
+ xpc_connection_cancel(peer);
507
+ return;
508
+ }
509
+ }
510
+
511
+ let daemon_inner = daemon_outer.clone();
512
+ let handle_inner = handle_outer.clone();
513
+ let peer_blocks_for_callback = peer_blocks_for_listener.clone();
514
+ let peer_blocks_for_insert = peer_blocks_for_listener.clone();
515
+ let peer_key = peer as usize;
516
+ let peer_block = ConcreteBlock::new(move |message: XpcObject| {
517
+ if !ptr::eq(xpc_get_type(message), &_xpc_type_dictionary) {
518
+ if let Ok(mut blocks) = peer_blocks_for_callback.lock() {
519
+ blocks.remove(&peer_key);
520
+ }
521
+ return;
522
+ }
523
+
524
+ let response = match decode_wire_request(message) {
525
+ Ok(request) => {
526
+ let mut request = request;
527
+ let daemon_request: Result<DaemonRpcRequest, XpcTransportError> =
528
+ serde_json::from_str(&request.body_json).map_err(|err| {
529
+ XpcTransportError::Serialization(err.to_string())
530
+ });
531
+ request.body_json.zeroize();
532
+
533
+ match daemon_request {
534
+ Ok(req) => {
535
+ match handle_inner.block_on(daemon_inner.handle_rpc(req)) {
536
+ Ok(resp) => {
537
+ let mut resp = resp;
538
+ match serde_json::to_string(&resp) {
539
+ Ok(body_json) => {
540
+ resp.zeroize_secrets();
541
+ WireResponse {
542
+ request_id: request.request_id,
543
+ ok: true,
544
+ body_json,
545
+ }
546
+ }
547
+ Err(err) => {
548
+ resp.zeroize_secrets();
549
+ WireResponse {
550
+ request_id: request.request_id,
551
+ ok: false,
552
+ body_json: format!(
553
+ "failed to serialize daemon response: {err}"
554
+ ),
555
+ }
556
+ }
557
+ }
558
+ }
559
+ Err(err) => WireResponse {
560
+ request_id: request.request_id,
561
+ ok: false,
562
+ body_json: serialize_wire_daemon_error(err),
563
+ },
564
+ }
565
+ }
566
+ Err(err) => WireResponse {
567
+ request_id: request.request_id,
568
+ ok: false,
569
+ body_json: err.to_string(),
570
+ },
571
+ }
572
+ }
573
+ Err(err) => WireResponse {
574
+ request_id: extract_safe_request_id(message),
575
+ ok: false,
576
+ body_json: err.to_string(),
577
+ },
578
+ };
579
+ let mut response = enforce_wire_response_limits(response);
580
+
581
+ let encoded = encode_wire_response(&response);
582
+ response.body_json.zeroize();
583
+ if let Ok(xpc_resp) = encoded {
584
+ xpc_connection_send_message(peer, xpc_resp);
585
+ xpc_release(xpc_resp);
586
+ }
587
+ })
588
+ .copy();
589
+
590
+ xpc_connection_set_event_handler(
591
+ peer,
592
+ &*peer_block as *const Block<_, _> as *mut c_void,
593
+ );
594
+ xpc_connection_resume(peer);
595
+ if let Ok(mut blocks) = peer_blocks_for_insert.lock() {
596
+ blocks.insert(peer_key, SendablePeerBlock { _block: peer_block });
597
+ };
598
+ })
599
+ .copy();
600
+
601
+ xpc_connection_set_event_handler(
602
+ listener,
603
+ &*listener_block as *const Block<_, _> as *mut c_void,
604
+ );
605
+ xpc_connection_resume(listener);
606
+
607
+ let endpoint_raw = xpc_endpoint_create(listener);
608
+ if endpoint_raw.is_null() {
609
+ return Err(XpcTransportError::Internal(
610
+ "xpc_endpoint_create returned null".to_string(),
611
+ ));
612
+ }
613
+
614
+ xpc_retain(listener);
615
+ xpc_retain(endpoint_raw);
616
+
617
+ Ok(Self {
618
+ listener,
619
+ endpoint: XpcEndpoint { raw: endpoint_raw },
620
+ _listener_block: listener_block,
621
+ _peer_blocks: peer_blocks,
622
+ })
623
+ }
624
+ }
625
+
626
+ /// Returns endpoint handle for clients.
627
+ #[must_use]
628
+ pub fn endpoint(&self) -> XpcEndpoint {
629
+ self.endpoint.clone()
630
+ }
631
+ }
632
+
633
+ #[cfg(target_os = "macos")]
634
+ fn parse_code_sign_requirement(requirement: &str) -> Result<SecRequirement, XpcTransportError> {
635
+ requirement
636
+ .parse::<SecRequirement>()
637
+ .map_err(|err| XpcTransportError::CodeSigning(format!("invalid requirement string: {err}")))
638
+ }
639
+
640
+ #[cfg(target_os = "macos")]
641
+ fn verify_peer_code_signing_requirement(
642
+ peer: XpcConnection,
643
+ requirement: &str,
644
+ ) -> Result<(), XpcTransportError> {
645
+ let pid = unsafe { xpc_connection_get_pid(peer) };
646
+ if pid <= 0 {
647
+ return Err(XpcTransportError::CodeSigning(
648
+ "peer pid is unavailable".to_string(),
649
+ ));
650
+ }
651
+
652
+ let mut attributes = GuestAttributes::new();
653
+ attributes.set_pid(pid);
654
+
655
+ let peer_code = SecCode::copy_guest_with_attribues(None, &attributes, CodeSignFlags::default())
656
+ .map_err(|err| {
657
+ XpcTransportError::CodeSigning(format!(
658
+ "failed to resolve peer code object for pid {pid}: {err}"
659
+ ))
660
+ })?;
661
+ let requirement = parse_code_sign_requirement(requirement)?;
662
+
663
+ peer_code
664
+ .check_validity(
665
+ CodeSignFlags::STRICT_VALIDATE | CodeSignFlags::CHECK_TRUSTED_ANCHORS,
666
+ &requirement,
667
+ )
668
+ .map_err(|err| {
669
+ XpcTransportError::CodeSigning(format!(
670
+ "peer code signature does not satisfy required policy for pid {pid}: {err}"
671
+ ))
672
+ })
673
+ }
674
+
675
+ #[cfg(target_os = "macos")]
676
+
677
+ include!("client_codec_api.rs");
678
+
679
+ #[cfg(all(test, target_os = "macos"))]
680
+ mod tests;