aquaman-proxy 0.13.0 → 0.13.1

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 (42) hide show
  1. package/README.md +1 -1
  2. package/dist/cli/index.js +69 -101
  3. package/dist/cli/index.js.map +1 -1
  4. package/dist/core/audit/logger.js +1 -1
  5. package/dist/core/audit/logger.js.map +1 -1
  6. package/dist/core/credentials/backends/onepassword.js +1 -1
  7. package/dist/core/credentials/backends/onepassword.js.map +1 -1
  8. package/dist/core/credentials/backends/systemd-creds.js +1 -1
  9. package/dist/core/credentials/backends/systemd-creds.js.map +1 -1
  10. package/dist/core/credentials/caching-store.d.ts +43 -0
  11. package/dist/core/credentials/caching-store.d.ts.map +1 -0
  12. package/dist/core/credentials/caching-store.js +77 -0
  13. package/dist/core/credentials/caching-store.js.map +1 -0
  14. package/dist/core/credentials/index.d.ts +1 -0
  15. package/dist/core/credentials/index.d.ts.map +1 -1
  16. package/dist/core/credentials/index.js +1 -0
  17. package/dist/core/credentials/index.js.map +1 -1
  18. package/dist/core/index.d.ts +2 -2
  19. package/dist/core/index.d.ts.map +1 -1
  20. package/dist/core/index.js +2 -2
  21. package/dist/core/index.js.map +1 -1
  22. package/dist/core/types.d.ts +9 -0
  23. package/dist/core/types.d.ts.map +1 -1
  24. package/dist/core/utils/config.d.ts +17 -0
  25. package/dist/core/utils/config.d.ts.map +1 -1
  26. package/dist/core/utils/config.js +33 -1
  27. package/dist/core/utils/config.js.map +1 -1
  28. package/dist/core/utils/index.d.ts +1 -1
  29. package/dist/core/utils/index.d.ts.map +1 -1
  30. package/dist/core/utils/index.js +1 -1
  31. package/dist/core/utils/index.js.map +1 -1
  32. package/dist/hermes/config-writer.d.ts +10 -0
  33. package/dist/hermes/config-writer.d.ts.map +1 -1
  34. package/dist/hermes/config-writer.js +25 -0
  35. package/dist/hermes/config-writer.js.map +1 -1
  36. package/dist/index.d.ts +1 -1
  37. package/dist/index.d.ts.map +1 -1
  38. package/dist/index.js +1 -1
  39. package/dist/index.js.map +1 -1
  40. package/dist/openclaw/integration.d.ts.map +1 -1
  41. package/dist/openclaw/integration.js.map +1 -1
  42. package/package.json +3 -3
package/README.md CHANGED
@@ -18,7 +18,7 @@ Agent / OpenClaw / Coding Agent Aquaman Proxy
18
18
  │ No credentials. │ proxy.sock │ │
19
19
  │ No open ports. │ (chmod 0o600) │ │
20
20
  │ Nothing to steal. │ │ │
21
- └──────────────────────┘ └───┬──────────┬───────┘
21
+ └──────────────────────┘ └──┬──────────┬────────┘
22
22
  │ │
23
23
  │ ▼
24
24
  │ ~/.aquaman/audit/
package/dist/cli/index.js CHANGED
@@ -12,12 +12,13 @@ import { Command, Help } from 'commander';
12
12
  import * as path from 'node:path';
13
13
  import * as fs from 'node:fs';
14
14
  import * as http from 'node:http';
15
- import { loadConfig, getConfigDir, ensureConfigDir, getDefaultConfig, expandPath, createAuditLogger, createCredentialStore, saveConfig, generateLoopbackToken, DEFAULT_LOOPBACK_PORT } from '../core/index.js';
15
+ import { loadConfig, getConfigDir, ensureConfigDir, getDefaultConfig, expandPath, createAuditLogger, createCredentialStore, saveConfig, generateLoopbackToken, DEFAULT_LOOPBACK_PORT, wrapWithCache, resolveCacheTtl } from '../core/index.js';
16
16
  import { fileURLToPath } from 'node:url';
17
17
  import { createCredentialProxy } from '../daemon.js';
18
18
  import { createServiceRegistry, ServiceRegistry } from '../service-registry.js';
19
19
  import { createOpenClawIntegration, authProfilesAreSqliteOnly } from '../openclaw/integration.js';
20
20
  import { createHermesIntegration, detectHermes } from '../hermes/integration.js';
21
+ import { managedScopeShadowedKeys, HERMES_MANAGED_ENV_PATH } from '../hermes/config-writer.js';
21
22
  import { loadPolicyFromConfig, validatePolicyConfig, getDefaultPolicyPresets, matchPolicy } from '../request-policy.js';
22
23
  import { stringify as yamlStringify, parse as yamlParse } from 'yaml';
23
24
  // Read version from package.json (single source of truth)
@@ -38,6 +39,49 @@ function validateCredName(label, value) {
38
39
  process.exit(1);
39
40
  }
40
41
  }
42
+ /**
43
+ * Soft hint for 1Password users running in biometric/desktop-app mode: every
44
+ * `op` spawn prompts, which makes unattended agents unusable. The daemon cache
45
+ * (v0.13.1+) bounds it to one prompt per TTL per credential; a service account
46
+ * removes prompts entirely. Printed by `aquaman doctor` and deep doctors.
47
+ */
48
+ function printOnePasswordModeHint(config, indent = ' ') {
49
+ if (config.credentials.backend !== '1password')
50
+ return;
51
+ if (process.env['OP_SERVICE_ACCOUNT_TOKEN'] || process.env['OP_CONNECT_HOST'])
52
+ return;
53
+ const vault = config.credentials.onePasswordVault || 'aquaman';
54
+ const ttl = resolveCacheTtl(config);
55
+ const cacheNote = ttl > 0
56
+ ? `the daemon cache bounds this to one per ${Math.round(ttl / 60)} min per credential`
57
+ : 'and the credential cache is disabled (cacheTtlSeconds: 0)';
58
+ console.log(`${indent}• 1Password is in biometric/desktop-app mode — each vault read prompts (${cacheNote}).`);
59
+ console.log(`${indent} For zero prompts, create a service account scoped to the "${vault}" vault (create the`);
60
+ console.log(`${indent} vault + credentials as a human first, or grant write_items) and start the daemon with`);
61
+ console.log(`${indent} OP_SERVICE_ACCOUNT_TOKEN. If OP_CONNECT_HOST/OP_CONNECT_TOKEN are set they take precedence.`);
62
+ }
63
+ /**
64
+ * Map config.credentials onto CredentialStoreOptions — the single source for
65
+ * every createCredentialStore() call in this CLI. Env fallbacks mirror
66
+ * applyEnvOverrides() (belt and braces for callers that build partial configs).
67
+ */
68
+ function storeOptionsFromConfig(config) {
69
+ return {
70
+ backend: config.credentials.backend,
71
+ encryptionPassword: config.credentials.encryptionPassword || process.env['AQUAMAN_ENCRYPTION_PASSWORD'] || process.env['AQUAMAN_KEEPASS_PASSWORD'],
72
+ vaultAddress: config.credentials.vaultAddress || process.env['VAULT_ADDR'],
73
+ vaultToken: config.credentials.vaultToken || process.env['VAULT_TOKEN'],
74
+ vaultNamespace: config.credentials.vaultNamespace,
75
+ vaultMountPath: config.credentials.vaultMountPath,
76
+ onePasswordVault: config.credentials.onePasswordVault,
77
+ onePasswordAccount: config.credentials.onePasswordAccount,
78
+ keepassxcDatabasePath: config.credentials.keepassxcDatabasePath,
79
+ keepassxcKeyFilePath: config.credentials.keepassxcKeyFilePath,
80
+ bitwardenFolder: config.credentials.bitwardenFolder,
81
+ bitwardenOrganizationId: config.credentials.bitwardenOrganizationId,
82
+ bitwardenCollectionId: config.credentials.bitwardenCollectionId
83
+ };
84
+ }
41
85
  /**
42
86
  * Build loopback listener options from config for the daemon. Returns undefined
43
87
  * unless the loopback listener is explicitly enabled. If it's enabled but no
@@ -310,21 +354,10 @@ program
310
354
  // Vault \u2014 backend + creds
311
355
  try {
312
356
  const config = loadConfig();
313
- const store = await createCredentialStore({
314
- backend: config.credentials.backend,
315
- encryptionPassword: config.credentials.encryptionPassword,
316
- vaultAddress: config.credentials.vaultAddress,
317
- vaultToken: config.credentials.vaultToken,
318
- onePasswordVault: config.credentials.onePasswordVault,
319
- onePasswordAccount: config.credentials.onePasswordAccount,
320
- keepassxcDatabasePath: config.credentials.keepassxcDatabasePath,
321
- keepassxcKeyFilePath: config.credentials.keepassxcKeyFilePath,
322
- bitwardenFolder: config.credentials.bitwardenFolder,
323
- bitwardenOrganizationId: config.credentials.bitwardenOrganizationId,
324
- bitwardenCollectionId: config.credentials.bitwardenCollectionId
325
- });
357
+ const store = await createCredentialStore(storeOptionsFromConfig(config));
326
358
  const creds = await store.list();
327
359
  console.log(` \u2713 ${config.credentials.backend} backend (${creds.length} credential${creds.length !== 1 ? 's' : ''})`);
360
+ printOnePasswordModeHint(config);
328
361
  }
329
362
  catch (err) {
330
363
  console.log(` \u2717 Backend not accessible: ${err.message}`);
@@ -528,19 +561,7 @@ async function runVaultSetup(opts) {
528
561
  fs.mkdirSync(auditDir, { recursive: true, mode: 0o700 });
529
562
  let store;
530
563
  try {
531
- store = await createCredentialStore({
532
- backend: config.credentials.backend,
533
- encryptionPassword: config.credentials.encryptionPassword || process.env['AQUAMAN_ENCRYPTION_PASSWORD'] || process.env['AQUAMAN_KEEPASS_PASSWORD'],
534
- vaultAddress: config.credentials.vaultAddress || process.env['VAULT_ADDR'],
535
- vaultToken: config.credentials.vaultToken || process.env['VAULT_TOKEN'],
536
- onePasswordVault: config.credentials.onePasswordVault,
537
- onePasswordAccount: config.credentials.onePasswordAccount,
538
- keepassxcDatabasePath: config.credentials.keepassxcDatabasePath,
539
- keepassxcKeyFilePath: config.credentials.keepassxcKeyFilePath,
540
- bitwardenFolder: config.credentials.bitwardenFolder,
541
- bitwardenOrganizationId: config.credentials.bitwardenOrganizationId,
542
- bitwardenCollectionId: config.credentials.bitwardenCollectionId
543
- });
564
+ store = await createCredentialStore(storeOptionsFromConfig(config));
544
565
  }
545
566
  catch (err) {
546
567
  console.error(` Failed to initialize ${backend}: ${err instanceof Error ? err.message : err}`);
@@ -666,21 +687,7 @@ openclaw
666
687
  // Initialize credential store
667
688
  let credentialStore;
668
689
  try {
669
- credentialStore = await createCredentialStore({
670
- backend: config.credentials.backend,
671
- encryptionPassword: config.credentials.encryptionPassword,
672
- vaultAddress: config.credentials.vaultAddress,
673
- vaultToken: config.credentials.vaultToken,
674
- vaultNamespace: config.credentials.vaultNamespace,
675
- vaultMountPath: config.credentials.vaultMountPath,
676
- onePasswordVault: config.credentials.onePasswordVault,
677
- onePasswordAccount: config.credentials.onePasswordAccount,
678
- keepassxcDatabasePath: config.credentials.keepassxcDatabasePath,
679
- keepassxcKeyFilePath: config.credentials.keepassxcKeyFilePath,
680
- bitwardenFolder: config.credentials.bitwardenFolder,
681
- bitwardenOrganizationId: config.credentials.bitwardenOrganizationId,
682
- bitwardenCollectionId: config.credentials.bitwardenCollectionId
683
- });
690
+ credentialStore = wrapWithCache(await createCredentialStore(storeOptionsFromConfig(config)), resolveCacheTtl(config));
684
691
  }
685
692
  catch (err) {
686
693
  console.error(`Credential backend "${config.credentials.backend}" failed to initialize: ${err instanceof Error ? err.message : err}`);
@@ -822,21 +829,7 @@ program
822
829
  // Initialize credential store
823
830
  let credentialStore;
824
831
  try {
825
- credentialStore = await createCredentialStore({
826
- backend: config.credentials.backend,
827
- encryptionPassword: config.credentials.encryptionPassword,
828
- vaultAddress: config.credentials.vaultAddress,
829
- vaultToken: config.credentials.vaultToken,
830
- vaultNamespace: config.credentials.vaultNamespace,
831
- vaultMountPath: config.credentials.vaultMountPath,
832
- onePasswordVault: config.credentials.onePasswordVault,
833
- onePasswordAccount: config.credentials.onePasswordAccount,
834
- keepassxcDatabasePath: config.credentials.keepassxcDatabasePath,
835
- keepassxcKeyFilePath: config.credentials.keepassxcKeyFilePath,
836
- bitwardenFolder: config.credentials.bitwardenFolder,
837
- bitwardenOrganizationId: config.credentials.bitwardenOrganizationId,
838
- bitwardenCollectionId: config.credentials.bitwardenCollectionId
839
- });
832
+ credentialStore = wrapWithCache(await createCredentialStore(storeOptionsFromConfig(config)), resolveCacheTtl(config));
840
833
  }
841
834
  catch (err) {
842
835
  console.error(`Credential backend "${config.credentials.backend}" failed to initialize: ${err instanceof Error ? err.message : err}`);
@@ -896,21 +889,7 @@ openclaw
896
889
  // Initialize credential store
897
890
  let credentialStore;
898
891
  try {
899
- credentialStore = await createCredentialStore({
900
- backend: config.credentials.backend,
901
- encryptionPassword: config.credentials.encryptionPassword,
902
- vaultAddress: config.credentials.vaultAddress,
903
- vaultToken: config.credentials.vaultToken,
904
- vaultNamespace: config.credentials.vaultNamespace,
905
- vaultMountPath: config.credentials.vaultMountPath,
906
- onePasswordVault: config.credentials.onePasswordVault,
907
- onePasswordAccount: config.credentials.onePasswordAccount,
908
- keepassxcDatabasePath: config.credentials.keepassxcDatabasePath,
909
- keepassxcKeyFilePath: config.credentials.keepassxcKeyFilePath,
910
- bitwardenFolder: config.credentials.bitwardenFolder,
911
- bitwardenOrganizationId: config.credentials.bitwardenOrganizationId,
912
- bitwardenCollectionId: config.credentials.bitwardenCollectionId
913
- });
892
+ credentialStore = wrapWithCache(await createCredentialStore(storeOptionsFromConfig(config)), resolveCacheTtl(config));
914
893
  }
915
894
  catch (err) {
916
895
  console.error(`Credential backend "${config.credentials.backend}" failed to initialize: ${err instanceof Error ? err.message : err}`);
@@ -1104,6 +1083,10 @@ hermes
1104
1083
  }
1105
1084
  catch { /* unreadable */ }
1106
1085
  console.log(` ~/.hermes/.env: ${envWired ? aqua('wired') : 'not wired'} (${envPath})`);
1086
+ const shadowed = managedScopeShadowedKeys(integration.configureHermes());
1087
+ if (shadowed.length > 0) {
1088
+ console.log(` Managed scope: ⚠ ${HERMES_MANAGED_ENV_PATH} pins ${shadowed.join(', ')} — proxy bypassed for these keys`);
1089
+ }
1107
1090
  const info = await detectHermes(config.hermes?.binaryPath || 'hermes');
1108
1091
  console.log(` Hermes CLI: ${info.installed ? aqua(`v${info.version}`) : 'not found'}`);
1109
1092
  // Live liveness probe of the loopback listener (no token needed for _health).
@@ -1162,6 +1145,16 @@ hermes
1162
1145
  catch {
1163
1146
  fail(`Could not read ${envPath}`);
1164
1147
  }
1148
+ // 3b. Hermes >=0.17 managed scope: /etc/hermes/.env overrides ~/.hermes/.env
1149
+ {
1150
+ const shadowed = managedScopeShadowedKeys(integration.configureHermes());
1151
+ if (shadowed.length > 0) {
1152
+ fail(`Hermes managed scope (${HERMES_MANAGED_ENV_PATH}) pins ${shadowed.join(', ')} — it overrides ~/.hermes/.env, so the proxy is BYPASSED for these keys. Remove them from the managed file or point them at the proxy.`);
1153
+ }
1154
+ else {
1155
+ pass('No managed-scope override of aquaman env vars');
1156
+ }
1157
+ }
1165
1158
  // 4. Per-service vault credentials resolve
1166
1159
  const wired = integration.wiredServices();
1167
1160
  if (wired.length === 0) {
@@ -1169,21 +1162,7 @@ hermes
1169
1162
  }
1170
1163
  else {
1171
1164
  try {
1172
- const store = await createCredentialStore({
1173
- backend: config.credentials.backend,
1174
- encryptionPassword: config.credentials.encryptionPassword,
1175
- vaultAddress: config.credentials.vaultAddress,
1176
- vaultToken: config.credentials.vaultToken,
1177
- vaultNamespace: config.credentials.vaultNamespace,
1178
- vaultMountPath: config.credentials.vaultMountPath,
1179
- onePasswordVault: config.credentials.onePasswordVault,
1180
- onePasswordAccount: config.credentials.onePasswordAccount,
1181
- keepassxcDatabasePath: config.credentials.keepassxcDatabasePath,
1182
- keepassxcKeyFilePath: config.credentials.keepassxcKeyFilePath,
1183
- bitwardenFolder: config.credentials.bitwardenFolder,
1184
- bitwardenOrganizationId: config.credentials.bitwardenOrganizationId,
1185
- bitwardenCollectionId: config.credentials.bitwardenCollectionId,
1186
- });
1165
+ const store = await createCredentialStore(storeOptionsFromConfig(config));
1187
1166
  for (const svc of wired) {
1188
1167
  const val = await store.get(svc, 'api_key');
1189
1168
  if (val)
@@ -1191,6 +1170,7 @@ hermes
1191
1170
  else
1192
1171
  fail(`No credential for ${svc}/api_key — run: aquaman credentials add ${svc} api_key`);
1193
1172
  }
1173
+ printOnePasswordModeHint(config, ' ');
1194
1174
  }
1195
1175
  catch (err) {
1196
1176
  fail(`Vault backend "${config.credentials.backend}" failed: ${err instanceof Error ? err.message : err}`);
@@ -1379,7 +1359,7 @@ openclaw
1379
1359
  process.exit(1);
1380
1360
  }
1381
1361
  }
1382
- catch (err) {
1362
+ catch {
1383
1363
  console.error(` Cannot reach Vault at ${vaultAddr}.`);
1384
1364
  process.exit(1);
1385
1365
  }
@@ -1459,19 +1439,7 @@ openclaw
1459
1439
  // 3. Prompt for API keys (or read from env in non-interactive mode)
1460
1440
  let store;
1461
1441
  try {
1462
- store = await createCredentialStore({
1463
- backend: config.credentials.backend,
1464
- encryptionPassword: config.credentials.encryptionPassword || process.env['AQUAMAN_ENCRYPTION_PASSWORD'] || process.env['AQUAMAN_KEEPASS_PASSWORD'],
1465
- vaultAddress: config.credentials.vaultAddress || process.env['VAULT_ADDR'],
1466
- vaultToken: config.credentials.vaultToken || process.env['VAULT_TOKEN'],
1467
- onePasswordVault: config.credentials.onePasswordVault,
1468
- onePasswordAccount: config.credentials.onePasswordAccount,
1469
- keepassxcDatabasePath: config.credentials.keepassxcDatabasePath,
1470
- keepassxcKeyFilePath: config.credentials.keepassxcKeyFilePath,
1471
- bitwardenFolder: config.credentials.bitwardenFolder,
1472
- bitwardenOrganizationId: config.credentials.bitwardenOrganizationId,
1473
- bitwardenCollectionId: config.credentials.bitwardenCollectionId
1474
- });
1442
+ store = await createCredentialStore(storeOptionsFromConfig(config));
1475
1443
  }
1476
1444
  catch (err) {
1477
1445
  console.error(` Failed to initialize ${backend} credential store: ${err instanceof Error ? err.message : err}`);