@wlfi-agent/cli 1.4.16 → 1.4.18

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 (97) hide show
  1. package/Cargo.lock +26 -20
  2. package/Cargo.toml +1 -1
  3. package/README.md +61 -28
  4. package/crates/vault-cli-admin/src/io_utils.rs +149 -1
  5. package/crates/vault-cli-admin/src/main.rs +639 -16
  6. package/crates/vault-cli-admin/src/shared_config.rs +18 -18
  7. package/crates/vault-cli-admin/src/tui/token_rpc.rs +190 -3
  8. package/crates/vault-cli-admin/src/tui/utils.rs +59 -0
  9. package/crates/vault-cli-admin/src/tui.rs +1205 -120
  10. package/crates/vault-cli-agent/Cargo.toml +1 -0
  11. package/crates/vault-cli-agent/src/io_utils.rs +163 -2
  12. package/crates/vault-cli-agent/src/main.rs +648 -32
  13. package/crates/vault-cli-daemon/Cargo.toml +4 -0
  14. package/crates/vault-cli-daemon/src/main.rs +617 -67
  15. package/crates/vault-cli-daemon/src/relay_sync.rs +776 -4
  16. package/crates/vault-cli-daemon/tests/system_keychain_helper_acl.rs +5 -0
  17. package/crates/vault-daemon/src/daemon_parts/api_impl_and_utils.rs +32 -1
  18. package/crates/vault-daemon/src/persistence.rs +637 -100
  19. package/crates/vault-daemon/src/tests.rs +1013 -3
  20. package/crates/vault-daemon/src/tests_parts/part2.rs +99 -0
  21. package/crates/vault-daemon/src/tests_parts/part4.rs +11 -7
  22. package/crates/vault-domain/src/nonce.rs +4 -0
  23. package/crates/vault-domain/src/tests.rs +616 -0
  24. package/crates/vault-policy/src/engine.rs +55 -32
  25. package/crates/vault-policy/src/tests.rs +195 -0
  26. package/crates/vault-sdk-agent/src/lib.rs +415 -22
  27. package/crates/vault-signer/Cargo.toml +3 -0
  28. package/crates/vault-signer/src/lib.rs +266 -40
  29. package/crates/vault-transport-unix/src/lib.rs +653 -5
  30. package/crates/vault-transport-xpc/src/tests.rs +531 -3
  31. package/crates/vault-transport-xpc/tests/e2e_flow.rs +3 -0
  32. package/dist/cli.cjs +663 -190
  33. package/dist/cli.cjs.map +1 -1
  34. package/package.json +5 -2
  35. package/packages/cache/.turbo/turbo-build.log +53 -52
  36. package/packages/cache/coverage/clover.xml +529 -394
  37. package/packages/cache/coverage/coverage-final.json +2 -2
  38. package/packages/cache/coverage/index.html +21 -21
  39. package/packages/cache/coverage/src/client/index.html +1 -1
  40. package/packages/cache/coverage/src/client/index.ts.html +1 -1
  41. package/packages/cache/coverage/src/errors/index.html +1 -1
  42. package/packages/cache/coverage/src/errors/index.ts.html +12 -12
  43. package/packages/cache/coverage/src/index.html +1 -1
  44. package/packages/cache/coverage/src/index.ts.html +1 -1
  45. package/packages/cache/coverage/src/service/index.html +21 -21
  46. package/packages/cache/coverage/src/service/index.ts.html +769 -313
  47. package/packages/cache/dist/{chunk-QNK6GOTI.js → chunk-KC53LH5Z.js} +35 -2
  48. package/packages/cache/dist/chunk-KC53LH5Z.js.map +1 -0
  49. package/packages/cache/dist/{chunk-QF4XKEIA.cjs → chunk-UVU7VFE3.cjs} +35 -2
  50. package/packages/cache/dist/chunk-UVU7VFE3.cjs.map +1 -0
  51. package/packages/cache/dist/index.cjs +2 -2
  52. package/packages/cache/dist/index.js +1 -1
  53. package/packages/cache/dist/service/index.cjs +2 -2
  54. package/packages/cache/dist/service/index.js +1 -1
  55. package/packages/cache/node_modules/.bin/tsc +2 -2
  56. package/packages/cache/node_modules/.bin/tsserver +2 -2
  57. package/packages/cache/node_modules/.bin/tsup +2 -2
  58. package/packages/cache/node_modules/.bin/tsup-node +2 -2
  59. package/packages/cache/node_modules/.bin/vitest +4 -4
  60. package/packages/cache/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -1
  61. package/packages/cache/src/service/index.test.ts +165 -19
  62. package/packages/cache/src/service/index.ts +38 -1
  63. package/packages/config/.turbo/turbo-build.log +18 -17
  64. package/packages/config/dist/index.cjs +0 -17
  65. package/packages/config/dist/index.cjs.map +1 -1
  66. package/packages/config/src/index.ts +0 -17
  67. package/packages/rpc/.turbo/turbo-build.log +32 -31
  68. package/packages/rpc/dist/index.cjs +0 -17
  69. package/packages/rpc/dist/index.cjs.map +1 -1
  70. package/packages/rpc/src/index.js +1 -0
  71. package/packages/ui/.turbo/turbo-build.log +44 -43
  72. package/packages/ui/dist/components/badge.d.ts +1 -1
  73. package/packages/ui/dist/components/button.d.ts +1 -1
  74. package/packages/ui/node_modules/.bin/tsc +2 -2
  75. package/packages/ui/node_modules/.bin/tsserver +2 -2
  76. package/packages/ui/node_modules/.bin/tsup +2 -2
  77. package/packages/ui/node_modules/.bin/tsup-node +2 -2
  78. package/scripts/install-cli-launcher.mjs +37 -0
  79. package/scripts/install-rust-binaries.mjs +112 -0
  80. package/scripts/run-tests-isolated.mjs +210 -0
  81. package/src/cli.ts +310 -50
  82. package/src/lib/admin-reset.ts +15 -30
  83. package/src/lib/admin-setup.ts +246 -55
  84. package/src/lib/agent-auth-migrate.ts +5 -1
  85. package/src/lib/asset-broadcast.ts +15 -4
  86. package/src/lib/config-amounts.ts +6 -4
  87. package/src/lib/hidden-tty-prompt.js +1 -0
  88. package/src/lib/hidden-tty-prompt.ts +105 -0
  89. package/src/lib/keychain.ts +1 -0
  90. package/src/lib/local-admin-access.ts +4 -29
  91. package/src/lib/rust.ts +129 -33
  92. package/src/lib/signed-tx.ts +1 -0
  93. package/src/lib/sudo.ts +15 -5
  94. package/src/lib/wallet-profile.ts +3 -0
  95. package/src/lib/wallet-setup.ts +52 -0
  96. package/packages/cache/dist/chunk-QF4XKEIA.cjs.map +0 -1
  97. package/packages/cache/dist/chunk-QNK6GOTI.js.map +0 -1
@@ -7,6 +7,7 @@ authors.workspace = true
7
7
 
8
8
  [dependencies]
9
9
  anyhow.workspace = true
10
+ async-trait.workspace = true
10
11
  clap.workspace = true
11
12
  hex.workspace = true
12
13
  libc.workspace = true
@@ -80,13 +80,24 @@ fn read_secret_from_reader(mut reader: impl Read, label: &str) -> Result<String>
80
80
  #[cfg(test)]
81
81
  mod tests {
82
82
  use super::{
83
- ensure_output_parent, read_secret_from_reader, validate_secret, write_output_file,
83
+ emit_output, ensure_output_parent, is_symlink_path, print_agent_output,
84
+ read_secret_from_reader, resolve_agent_auth_token, resolve_output_target,
85
+ temporary_output_path, validate_secret, write_output_file,
84
86
  };
87
+ use crate::{AgentCommandOutput, OutputFormat, OutputTarget};
85
88
  use std::fs;
86
- use std::io::Cursor;
89
+ use std::io::{Cursor, Read};
87
90
  use std::path::PathBuf;
88
91
  use std::time::{SystemTime, UNIX_EPOCH};
89
92
 
93
+ struct FailingReader;
94
+
95
+ impl Read for FailingReader {
96
+ fn read(&mut self, _buf: &mut [u8]) -> std::io::Result<usize> {
97
+ Err(std::io::Error::other("boom"))
98
+ }
99
+ }
100
+
90
101
  fn temp_path(prefix: &str) -> PathBuf {
91
102
  std::env::temp_dir().join(format!(
92
103
  "{prefix}-{}-{}",
@@ -105,6 +116,25 @@ mod tests {
105
116
  assert!(err.to_string().contains("must not exceed"));
106
117
  }
107
118
 
119
+ #[test]
120
+ fn read_secret_from_reader_trims_newlines_and_rejects_blank_values() {
121
+ let trimmed = read_secret_from_reader(Cursor::new("agent-token\r\n"), "agent auth token")
122
+ .expect("trimmed token");
123
+ assert_eq!(trimmed, "agent-token");
124
+
125
+ let err = read_secret_from_reader(Cursor::new(" \n"), "agent auth token")
126
+ .expect_err("must fail");
127
+ assert!(err.to_string().contains("must not be empty or whitespace"));
128
+ }
129
+
130
+ #[test]
131
+ fn read_secret_from_reader_propagates_io_errors() {
132
+ let err = read_secret_from_reader(FailingReader, "agent auth token").expect_err("must fail");
133
+ assert!(err
134
+ .to_string()
135
+ .contains("failed to read agent auth token from stdin"));
136
+ }
137
+
108
138
  #[test]
109
139
  fn validate_secret_rejects_oversized_non_stdin_secret() {
110
140
  let err = validate_secret("a".repeat((16 * 1024) + 1), "argument or environment")
@@ -112,6 +142,22 @@ mod tests {
112
142
  assert!(err.to_string().contains("must not exceed"));
113
143
  }
114
144
 
145
+ #[test]
146
+ fn validate_secret_rejects_whitespace_only() {
147
+ let err = validate_secret(" \t ".to_string(), "environment").expect_err("must fail");
148
+ assert!(err.to_string().contains("must not be empty or whitespace"));
149
+ }
150
+
151
+ #[test]
152
+ fn resolve_agent_auth_token_covers_env_and_non_interactive_paths() {
153
+ let token = resolve_agent_auth_token(None, Some("secret".to_string()), false, false)
154
+ .expect("environment token");
155
+ assert_eq!(token, "secret");
156
+
157
+ let err = resolve_agent_auth_token(None, None, false, true).expect_err("must fail");
158
+ assert!(err.to_string().contains("agent auth token is required in non-interactive mode"));
159
+ }
160
+
115
161
  #[test]
116
162
  #[cfg(unix)]
117
163
  fn ensure_output_parent_rejects_symlinked_parent_directory() {
@@ -199,6 +245,36 @@ mod tests {
199
245
  fs::remove_dir_all(&root).expect("cleanup temp tree");
200
246
  }
201
247
 
248
+ #[test]
249
+ fn ensure_output_parent_rejects_directory_output_path() {
250
+ let root = temp_path("vault-cli-agent-output-directory");
251
+ fs::create_dir_all(&root).expect("create root directory");
252
+
253
+ let err = ensure_output_parent(&root).expect_err("must reject directory path");
254
+ assert!(err.to_string().contains("is a directory; provide a file path"));
255
+
256
+ fs::remove_dir_all(&root).expect("cleanup temp tree");
257
+ }
258
+
259
+ #[test]
260
+ #[cfg(unix)]
261
+ fn ensure_output_parent_rejects_symlinked_output_path() {
262
+ use std::os::unix::fs::symlink;
263
+
264
+ let root = temp_path("vault-cli-agent-output-path-symlink");
265
+ fs::create_dir_all(&root).expect("create root directory");
266
+ let target = root.join("target.json");
267
+ let link = root.join("link.json");
268
+ fs::write(&target, "seed\n").expect("seed target");
269
+ symlink(&target, &link).expect("symlink output path");
270
+
271
+ let err = ensure_output_parent(&link).expect_err("must reject symlink path");
272
+ assert!(err.to_string().contains("must not be a symlink"));
273
+ assert!(is_symlink_path(&link).expect("symlink metadata"));
274
+
275
+ fs::remove_dir_all(&root).expect("cleanup temp tree");
276
+ }
277
+
202
278
  #[test]
203
279
  #[cfg(unix)]
204
280
  fn write_output_file_overwrite_replaces_existing_hard_link_instead_of_mutating_shared_inode() {
@@ -229,6 +305,91 @@ mod tests {
229
305
 
230
306
  fs::remove_dir_all(&root).expect("cleanup temp tree");
231
307
  }
308
+
309
+ #[test]
310
+ fn resolve_output_target_preserves_file_paths() {
311
+ let path = temp_path("vault-cli-agent-output-target");
312
+ let target = resolve_output_target(Some(path.clone()), true).expect("target");
313
+ match target {
314
+ OutputTarget::File { path: actual, overwrite } => {
315
+ assert_eq!(actual, path);
316
+ assert!(overwrite);
317
+ }
318
+ OutputTarget::Stdout => panic!("expected file target"),
319
+ }
320
+ }
321
+
322
+ #[test]
323
+ fn emit_output_and_print_agent_output_write_expected_content() {
324
+ let output_path = temp_path("vault-cli-agent-emit-output");
325
+ let agent_output_path = temp_path("vault-cli-agent-render-output");
326
+
327
+ emit_output(
328
+ "hello",
329
+ &OutputTarget::File {
330
+ path: output_path.clone(),
331
+ overwrite: false,
332
+ },
333
+ )
334
+ .expect("emit file output");
335
+ assert_eq!(fs::read_to_string(&output_path).expect("read output"), "hello\n");
336
+
337
+ let output = AgentCommandOutput {
338
+ command: "broadcast".to_string(),
339
+ network: "1".to_string(),
340
+ asset: "native_eth".to_string(),
341
+ counterparty: "0x2000000000000000000000000000000000000000".to_string(),
342
+ amount_wei: "7".to_string(),
343
+ estimated_max_gas_spend_wei: Some("21000".to_string()),
344
+ tx_type: Some("0x02".to_string()),
345
+ delegation_enabled: Some(false),
346
+ signature_hex: "0xdead".to_string(),
347
+ r_hex: Some("0x01".to_string()),
348
+ s_hex: Some("0x02".to_string()),
349
+ v: Some(1),
350
+ raw_tx_hex: Some("0xbeef".to_string()),
351
+ tx_hash_hex: Some("0xcafe".to_string()),
352
+ };
353
+
354
+ print_agent_output(
355
+ &output,
356
+ OutputFormat::Text,
357
+ &OutputTarget::File {
358
+ path: agent_output_path.clone(),
359
+ overwrite: false,
360
+ },
361
+ )
362
+ .expect("text render");
363
+ let rendered = fs::read_to_string(&agent_output_path).expect("read rendered");
364
+ assert!(rendered.contains("Command: broadcast"));
365
+ assert!(rendered.contains("Estimated Max Gas Spend (wei): 21000"));
366
+ assert!(rendered.contains("Delegation Enabled: false"));
367
+ assert!(rendered.contains("Tx Hash: 0xcafe"));
368
+
369
+ print_agent_output(
370
+ &output,
371
+ OutputFormat::Json,
372
+ &OutputTarget::File {
373
+ path: agent_output_path.clone(),
374
+ overwrite: true,
375
+ },
376
+ )
377
+ .expect("json render");
378
+ let rendered = fs::read_to_string(&agent_output_path).expect("read rendered");
379
+ assert!(rendered.contains("\"command\": \"broadcast\""));
380
+ assert!(rendered.contains("\"tx_hash_hex\": \"0xcafe\""));
381
+
382
+ fs::remove_file(&output_path).expect("cleanup output");
383
+ fs::remove_file(&agent_output_path).expect("cleanup rendered");
384
+ }
385
+
386
+ #[test]
387
+ fn temporary_output_path_stays_in_parent_directory() {
388
+ let output = temp_path("vault-cli-agent-temp-output");
389
+ let temp = temporary_output_path(&output);
390
+ assert_eq!(temp.parent(), output.parent());
391
+ assert!(temp.file_name().expect("file name").to_string_lossy().contains(".tmp-"));
392
+ }
232
393
  }
233
394
 
234
395
  pub(crate) fn resolve_output_format(