@zincapp/zn-vault-agent 1.3.0

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 (88) hide show
  1. package/README.md +701 -0
  2. package/deploy/logrotate.d/zn-vault-agent +14 -0
  3. package/deploy/systemd/zn-vault-agent.service +75 -0
  4. package/dist/commands/certs.d.ts +3 -0
  5. package/dist/commands/certs.d.ts.map +1 -0
  6. package/dist/commands/certs.js +369 -0
  7. package/dist/commands/certs.js.map +1 -0
  8. package/dist/commands/exec.d.ts +3 -0
  9. package/dist/commands/exec.d.ts.map +1 -0
  10. package/dist/commands/exec.js +193 -0
  11. package/dist/commands/exec.js.map +1 -0
  12. package/dist/commands/login.d.ts +3 -0
  13. package/dist/commands/login.d.ts.map +1 -0
  14. package/dist/commands/login.js +234 -0
  15. package/dist/commands/login.js.map +1 -0
  16. package/dist/commands/secrets.d.ts +3 -0
  17. package/dist/commands/secrets.d.ts.map +1 -0
  18. package/dist/commands/secrets.js +445 -0
  19. package/dist/commands/secrets.js.map +1 -0
  20. package/dist/commands/setup.d.ts +9 -0
  21. package/dist/commands/setup.d.ts.map +1 -0
  22. package/dist/commands/setup.js +346 -0
  23. package/dist/commands/setup.js.map +1 -0
  24. package/dist/commands/start.d.ts +3 -0
  25. package/dist/commands/start.d.ts.map +1 -0
  26. package/dist/commands/start.js +113 -0
  27. package/dist/commands/start.js.map +1 -0
  28. package/dist/commands/status.d.ts +3 -0
  29. package/dist/commands/status.d.ts.map +1 -0
  30. package/dist/commands/status.js +85 -0
  31. package/dist/commands/status.js.map +1 -0
  32. package/dist/commands/sync.d.ts +3 -0
  33. package/dist/commands/sync.d.ts.map +1 -0
  34. package/dist/commands/sync.js +126 -0
  35. package/dist/commands/sync.js.map +1 -0
  36. package/dist/index.d.ts +3 -0
  37. package/dist/index.d.ts.map +1 -0
  38. package/dist/index.js +28 -0
  39. package/dist/index.js.map +1 -0
  40. package/dist/lib/api.d.ts +104 -0
  41. package/dist/lib/api.d.ts.map +1 -0
  42. package/dist/lib/api.js +338 -0
  43. package/dist/lib/api.js.map +1 -0
  44. package/dist/lib/config.d.ts +164 -0
  45. package/dist/lib/config.d.ts.map +1 -0
  46. package/dist/lib/config.js +299 -0
  47. package/dist/lib/config.js.map +1 -0
  48. package/dist/lib/deployer.d.ts +22 -0
  49. package/dist/lib/deployer.d.ts.map +1 -0
  50. package/dist/lib/deployer.js +407 -0
  51. package/dist/lib/deployer.js.map +1 -0
  52. package/dist/lib/health.d.ts +68 -0
  53. package/dist/lib/health.d.ts.map +1 -0
  54. package/dist/lib/health.js +216 -0
  55. package/dist/lib/health.js.map +1 -0
  56. package/dist/lib/logger.d.ts +38 -0
  57. package/dist/lib/logger.d.ts.map +1 -0
  58. package/dist/lib/logger.js +161 -0
  59. package/dist/lib/logger.js.map +1 -0
  60. package/dist/lib/metrics.d.ts +50 -0
  61. package/dist/lib/metrics.d.ts.map +1 -0
  62. package/dist/lib/metrics.js +273 -0
  63. package/dist/lib/metrics.js.map +1 -0
  64. package/dist/lib/secret-deployer.d.ts +22 -0
  65. package/dist/lib/secret-deployer.d.ts.map +1 -0
  66. package/dist/lib/secret-deployer.js +201 -0
  67. package/dist/lib/secret-deployer.js.map +1 -0
  68. package/dist/lib/validation.d.ts +25 -0
  69. package/dist/lib/validation.d.ts.map +1 -0
  70. package/dist/lib/validation.js +257 -0
  71. package/dist/lib/validation.js.map +1 -0
  72. package/dist/lib/websocket.d.ts +74 -0
  73. package/dist/lib/websocket.d.ts.map +1 -0
  74. package/dist/lib/websocket.js +441 -0
  75. package/dist/lib/websocket.js.map +1 -0
  76. package/dist/services/api-key-renewal.d.ts +13 -0
  77. package/dist/services/api-key-renewal.d.ts.map +1 -0
  78. package/dist/services/api-key-renewal.js +204 -0
  79. package/dist/services/api-key-renewal.js.map +1 -0
  80. package/dist/services/npm-auto-update.d.ts +60 -0
  81. package/dist/services/npm-auto-update.d.ts.map +1 -0
  82. package/dist/services/npm-auto-update.js +245 -0
  83. package/dist/services/npm-auto-update.js.map +1 -0
  84. package/dist/types/update.d.ts +19 -0
  85. package/dist/types/update.d.ts.map +1 -0
  86. package/dist/types/update.js +7 -0
  87. package/dist/types/update.js.map +1 -0
  88. package/package.json +74 -0
@@ -0,0 +1,75 @@
1
+ [Unit]
2
+ Description=ZN-Vault Certificate Agent
3
+ Documentation=https://github.com/zincapp/zn-vault
4
+ After=network-online.target
5
+ Wants=network-online.target
6
+
7
+ [Service]
8
+ Type=simple
9
+ User=zn-vault-agent
10
+ Group=zn-vault-agent
11
+
12
+ # Working directory
13
+ WorkingDirectory=/var/lib/zn-vault-agent
14
+
15
+ # Main executable
16
+ ExecStart=/usr/local/bin/zn-vault-agent start --health-port 9100
17
+
18
+ # Restart policy
19
+ Restart=always
20
+ RestartSec=5
21
+ StartLimitInterval=60
22
+ StartLimitBurst=5
23
+
24
+ # Environment
25
+ EnvironmentFile=/etc/zn-vault-agent/agent.env
26
+ EnvironmentFile=-/etc/zn-vault-agent/secrets.env
27
+
28
+ # Logging
29
+ StandardOutput=journal
30
+ StandardError=journal
31
+ SyslogIdentifier=zn-vault-agent
32
+
33
+ # Shutdown
34
+ TimeoutStopSec=30
35
+ KillMode=mixed
36
+ KillSignal=SIGTERM
37
+
38
+ # Security hardening
39
+ NoNewPrivileges=true
40
+ ProtectSystem=strict
41
+ ProtectHome=true
42
+ PrivateTmp=true
43
+ PrivateDevices=true
44
+ ProtectKernelTunables=true
45
+ ProtectKernelModules=true
46
+ ProtectControlGroups=true
47
+ RestrictNamespaces=true
48
+ RestrictRealtime=true
49
+ RestrictSUIDSGID=true
50
+ LockPersonality=true
51
+
52
+ # Allow writing certificates and logs
53
+ ReadWritePaths=/etc/ssl/znvault
54
+ ReadWritePaths=/var/lib/zn-vault-agent
55
+ ReadWritePaths=/var/log/zn-vault-agent
56
+
57
+ # Network access
58
+ RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX
59
+
60
+ # System call filter
61
+ SystemCallFilter=@system-service
62
+ SystemCallFilter=~@privileged @resources
63
+ SystemCallArchitectures=native
64
+
65
+ # Capabilities
66
+ CapabilityBoundingSet=
67
+ AmbientCapabilities=
68
+
69
+ # Resource limits
70
+ MemoryHigh=256M
71
+ MemoryMax=512M
72
+ LimitNOFILE=4096
73
+
74
+ [Install]
75
+ WantedBy=multi-user.target
@@ -0,0 +1,3 @@
1
+ import { Command } from 'commander';
2
+ export declare function registerCertsCommands(program: Command): void;
3
+ //# sourceMappingURL=certs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"certs.d.ts","sourceRoot":"","sources":["../../src/commands/certs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAcpC,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAsY5D"}
@@ -0,0 +1,369 @@
1
+ import inquirer from 'inquirer';
2
+ import ora from 'ora';
3
+ import chalk from 'chalk';
4
+ import { addTarget, removeTarget, getTargets, isConfigured, } from '../lib/config.js';
5
+ import { listCertificates, getCertificate } from '../lib/api.js';
6
+ export function registerCertsCommands(program) {
7
+ // List available certificates in vault
8
+ program
9
+ .command('available')
10
+ .description('List certificates available in vault')
11
+ .option('--json', 'Output as JSON')
12
+ .addHelpText('after', `
13
+ Examples:
14
+ zn-vault-agent available # Human-readable list with status
15
+ zn-vault-agent available --json # JSON output for scripting
16
+ `)
17
+ .action(async (options) => {
18
+ if (!isConfigured()) {
19
+ console.error(chalk.red('Not configured. Run: zn-vault-agent login'));
20
+ process.exit(1);
21
+ }
22
+ const spinner = ora('Fetching certificates...').start();
23
+ try {
24
+ const result = await listCertificates();
25
+ spinner.stop();
26
+ if (options.json) {
27
+ console.log(JSON.stringify(result.items, null, 2));
28
+ return;
29
+ }
30
+ if (result.items.length === 0) {
31
+ console.log('No certificates found in vault');
32
+ return;
33
+ }
34
+ console.log();
35
+ console.log(chalk.bold('Available Certificates'));
36
+ console.log();
37
+ const targets = getTargets();
38
+ const configuredIds = new Set(targets.map(t => t.certId));
39
+ for (const cert of result.items) {
40
+ const configured = configuredIds.has(cert.id);
41
+ const status = configured ? chalk.green('✓ configured') : chalk.gray('not configured');
42
+ const expiry = cert.daysUntilExpiry < 30
43
+ ? chalk.yellow(`${cert.daysUntilExpiry}d`)
44
+ : `${cert.daysUntilExpiry}d`;
45
+ console.log(` ${cert.id.substring(0, 8)} ${cert.alias.padEnd(25)} ${status}`);
46
+ console.log(` ${chalk.gray(cert.subjectCn)} (expires: ${expiry})`);
47
+ console.log();
48
+ }
49
+ console.log(`Total: ${result.total} certificate(s)`);
50
+ }
51
+ catch (err) {
52
+ spinner.fail('Failed to fetch certificates');
53
+ console.error(chalk.red('Error:'), err instanceof Error ? err.message : String(err));
54
+ process.exit(1);
55
+ }
56
+ });
57
+ // Add a certificate target
58
+ program
59
+ .command('add')
60
+ .description('Add a certificate to sync')
61
+ .option('-c, --cert <id>', 'Certificate ID')
62
+ .option('-n, --name <name>', 'Local name for this certificate')
63
+ .option('--combined <path>', 'Path for combined cert+key file (HAProxy)')
64
+ .option('--cert-file <path>', 'Path for certificate file')
65
+ .option('--key-file <path>', 'Path for private key file')
66
+ .option('--chain-file <path>', 'Path for CA chain file')
67
+ .option('--fullchain-file <path>', 'Path for fullchain file')
68
+ .option('--owner <user:group>', 'File ownership (e.g., haproxy:haproxy)')
69
+ .option('--mode <mode>', 'File permissions (e.g., 0640)')
70
+ .option('--reload-cmd <cmd>', 'Command to reload service')
71
+ .option('--health-cmd <cmd>', 'Health check command after reload')
72
+ .addHelpText('after', `
73
+ Examples:
74
+ # Interactive mode (prompts for all options)
75
+ zn-vault-agent add
76
+
77
+ # HAProxy: combined cert+key file
78
+ zn-vault-agent add --cert $CERT_ID \\
79
+ --name haproxy-frontend \\
80
+ --combined /etc/haproxy/certs/frontend.pem \\
81
+ --owner haproxy:haproxy --mode 0640 \\
82
+ --reload-cmd "systemctl reload haproxy"
83
+
84
+ # Nginx: separate fullchain and key files
85
+ zn-vault-agent add --cert $CERT_ID \\
86
+ --name nginx-api \\
87
+ --fullchain-file /etc/nginx/ssl/api-fullchain.pem \\
88
+ --key-file /etc/nginx/ssl/api.key \\
89
+ --reload-cmd "nginx -t && systemctl reload nginx"
90
+
91
+ # With health check
92
+ zn-vault-agent add --cert $CERT_ID \\
93
+ --name app-server \\
94
+ --combined /etc/ssl/app.pem \\
95
+ --reload-cmd "systemctl restart app" \\
96
+ --health-cmd "curl -sf http://localhost:8080/health"
97
+ `)
98
+ .action(async (options) => {
99
+ if (!isConfigured()) {
100
+ console.error(chalk.red('Not configured. Run: zn-vault-agent login'));
101
+ process.exit(1);
102
+ }
103
+ // If cert ID not provided, show selection
104
+ let certId = options.cert;
105
+ let certAlias = '';
106
+ if (!certId) {
107
+ const spinner = ora('Fetching certificates...').start();
108
+ const result = await listCertificates();
109
+ spinner.stop();
110
+ if (result.items.length === 0) {
111
+ console.log('No certificates found in vault');
112
+ process.exit(1);
113
+ }
114
+ const { selectedCert } = await inquirer.prompt([
115
+ {
116
+ type: 'list',
117
+ name: 'selectedCert',
118
+ message: 'Select certificate to add:',
119
+ choices: result.items.map(c => ({
120
+ name: `${c.alias} (${c.subjectCn}) - expires in ${c.daysUntilExpiry}d`,
121
+ value: c.id,
122
+ })),
123
+ },
124
+ ]);
125
+ certId = selectedCert;
126
+ certAlias = result.items.find(c => c.id === certId)?.alias || '';
127
+ }
128
+ // Get certificate details
129
+ const spinner = ora('Fetching certificate details...').start();
130
+ const cert = await getCertificate(certId);
131
+ spinner.stop();
132
+ console.log();
133
+ console.log(chalk.bold('Certificate:'), cert.alias);
134
+ console.log(chalk.gray(`Subject: ${cert.subjectCn}`));
135
+ console.log(chalk.gray(`Expires: ${cert.daysUntilExpiry} days`));
136
+ console.log();
137
+ // Gather output configuration
138
+ const answers = await inquirer.prompt([
139
+ {
140
+ type: 'input',
141
+ name: 'name',
142
+ message: 'Local name for this target:',
143
+ default: options.name || cert.alias.replace(/[^a-zA-Z0-9-_]/g, '-'),
144
+ },
145
+ {
146
+ type: 'list',
147
+ name: 'outputFormat',
148
+ message: 'Output format:',
149
+ choices: [
150
+ { name: 'Combined (cert+key in one file) - for HAProxy', value: 'combined' },
151
+ { name: 'Separate files (cert, key, chain)', value: 'separate' },
152
+ { name: 'Custom', value: 'custom' },
153
+ ],
154
+ },
155
+ {
156
+ type: 'input',
157
+ name: 'combined',
158
+ message: 'Combined file path:',
159
+ when: (ans) => ans.outputFormat === 'combined',
160
+ default: options.combined || `/etc/ssl/${cert.alias}.pem`,
161
+ },
162
+ {
163
+ type: 'input',
164
+ name: 'certFile',
165
+ message: 'Certificate file path:',
166
+ when: (ans) => ans.outputFormat === 'separate',
167
+ default: options.certFile || `/etc/ssl/certs/${cert.alias}.crt`,
168
+ },
169
+ {
170
+ type: 'input',
171
+ name: 'keyFile',
172
+ message: 'Private key file path:',
173
+ when: (ans) => ans.outputFormat === 'separate',
174
+ default: options.keyFile || `/etc/ssl/private/${cert.alias}.key`,
175
+ },
176
+ {
177
+ type: 'input',
178
+ name: 'chainFile',
179
+ message: 'CA chain file path (optional):',
180
+ when: (ans) => ans.outputFormat === 'separate',
181
+ default: options.chainFile || '',
182
+ },
183
+ {
184
+ type: 'input',
185
+ name: 'owner',
186
+ message: 'File ownership (user:group):',
187
+ default: options.owner || 'root:root',
188
+ },
189
+ {
190
+ type: 'input',
191
+ name: 'mode',
192
+ message: 'File permissions:',
193
+ default: options.mode || '0640',
194
+ },
195
+ {
196
+ type: 'input',
197
+ name: 'reloadCmd',
198
+ message: 'Reload command (run after cert update):',
199
+ default: options.reloadCmd || 'systemctl reload haproxy',
200
+ },
201
+ {
202
+ type: 'input',
203
+ name: 'healthCmd',
204
+ message: 'Health check command (optional):',
205
+ default: options.healthCmd || '',
206
+ },
207
+ ]);
208
+ // Build target configuration
209
+ const target = {
210
+ certId,
211
+ name: answers.name,
212
+ outputs: {},
213
+ owner: answers.owner,
214
+ mode: answers.mode,
215
+ reloadCmd: answers.reloadCmd || undefined,
216
+ healthCheckCmd: answers.healthCmd || undefined,
217
+ };
218
+ if (answers.outputFormat === 'combined' || options.combined) {
219
+ target.outputs.combined = answers.combined || options.combined;
220
+ }
221
+ if (answers.certFile || options.certFile) {
222
+ target.outputs.cert = answers.certFile || options.certFile;
223
+ }
224
+ if (answers.keyFile || options.keyFile) {
225
+ target.outputs.key = answers.keyFile || options.keyFile;
226
+ }
227
+ if (answers.chainFile || options.chainFile) {
228
+ target.outputs.chain = answers.chainFile || options.chainFile;
229
+ }
230
+ if (options.fullchainFile) {
231
+ target.outputs.fullchain = options.fullchainFile;
232
+ }
233
+ // Handle custom output
234
+ if (answers.outputFormat === 'custom') {
235
+ const customAnswers = await inquirer.prompt([
236
+ {
237
+ type: 'input',
238
+ name: 'combined',
239
+ message: 'Combined file path (leave empty to skip):',
240
+ default: options.combined || '',
241
+ },
242
+ {
243
+ type: 'input',
244
+ name: 'cert',
245
+ message: 'Certificate file path (leave empty to skip):',
246
+ default: options.certFile || '',
247
+ },
248
+ {
249
+ type: 'input',
250
+ name: 'key',
251
+ message: 'Private key file path (leave empty to skip):',
252
+ default: options.keyFile || '',
253
+ },
254
+ {
255
+ type: 'input',
256
+ name: 'chain',
257
+ message: 'CA chain file path (leave empty to skip):',
258
+ default: options.chainFile || '',
259
+ },
260
+ {
261
+ type: 'input',
262
+ name: 'fullchain',
263
+ message: 'Fullchain file path (leave empty to skip):',
264
+ default: options.fullchainFile || '',
265
+ },
266
+ ]);
267
+ if (customAnswers.combined)
268
+ target.outputs.combined = customAnswers.combined;
269
+ if (customAnswers.cert)
270
+ target.outputs.cert = customAnswers.cert;
271
+ if (customAnswers.key)
272
+ target.outputs.key = customAnswers.key;
273
+ if (customAnswers.chain)
274
+ target.outputs.chain = customAnswers.chain;
275
+ if (customAnswers.fullchain)
276
+ target.outputs.fullchain = customAnswers.fullchain;
277
+ }
278
+ // Save target
279
+ addTarget(target);
280
+ console.log();
281
+ console.log(chalk.green('✓') + ` Certificate target "${answers.name}" added`);
282
+ console.log();
283
+ console.log('Output files:');
284
+ for (const [type, path] of Object.entries(target.outputs)) {
285
+ if (path)
286
+ console.log(` ${type}: ${path}`);
287
+ }
288
+ console.log();
289
+ console.log('Run ' + chalk.cyan('zn-vault-agent sync') + ' to deploy now');
290
+ });
291
+ // List configured targets
292
+ program
293
+ .command('list')
294
+ .description('List configured certificate targets')
295
+ .option('--json', 'Output as JSON')
296
+ .addHelpText('after', `
297
+ Examples:
298
+ zn-vault-agent list # Human-readable list
299
+ zn-vault-agent list --json # JSON output for scripting
300
+ `)
301
+ .action(async (options) => {
302
+ const targets = getTargets();
303
+ if (options.json) {
304
+ console.log(JSON.stringify(targets, null, 2));
305
+ return;
306
+ }
307
+ if (targets.length === 0) {
308
+ console.log('No certificate targets configured.');
309
+ console.log('Run ' + chalk.cyan('zn-vault-agent add') + ' to add one.');
310
+ return;
311
+ }
312
+ console.log();
313
+ console.log(chalk.bold('Configured Certificate Targets'));
314
+ console.log();
315
+ for (const target of targets) {
316
+ const syncStatus = target.lastSync
317
+ ? chalk.green(`synced ${new Date(target.lastSync).toLocaleString()}`)
318
+ : chalk.yellow('not synced');
319
+ console.log(` ${chalk.bold(target.name)}`);
320
+ console.log(` Certificate: ${target.certId.substring(0, 8)}...`);
321
+ console.log(` Status: ${syncStatus}`);
322
+ console.log(` Outputs:`);
323
+ for (const [type, path] of Object.entries(target.outputs)) {
324
+ if (path)
325
+ console.log(` ${type}: ${path}`);
326
+ }
327
+ if (target.reloadCmd) {
328
+ console.log(` Reload: ${target.reloadCmd}`);
329
+ }
330
+ console.log();
331
+ }
332
+ console.log(`Total: ${targets.length} target(s)`);
333
+ });
334
+ // Remove a target
335
+ program
336
+ .command('remove <name>')
337
+ .description('Remove a certificate target')
338
+ .option('-f, --force', 'Skip confirmation')
339
+ .addHelpText('after', `
340
+ Examples:
341
+ zn-vault-agent remove haproxy-frontend # Interactive confirmation
342
+ zn-vault-agent remove haproxy-frontend --force # Skip confirmation
343
+ `)
344
+ .action(async (name, options) => {
345
+ const targets = getTargets();
346
+ const target = targets.find(t => t.name === name || t.certId === name);
347
+ if (!target) {
348
+ console.error(chalk.red(`Target "${name}" not found`));
349
+ process.exit(1);
350
+ }
351
+ if (!options.force) {
352
+ const { confirm } = await inquirer.prompt([
353
+ {
354
+ type: 'confirm',
355
+ name: 'confirm',
356
+ message: `Remove target "${target.name}"?`,
357
+ default: false,
358
+ },
359
+ ]);
360
+ if (!confirm) {
361
+ console.log('Cancelled');
362
+ return;
363
+ }
364
+ }
365
+ removeTarget(name);
366
+ console.log(chalk.green('✓') + ` Target "${target.name}" removed`);
367
+ });
368
+ }
369
+ //# sourceMappingURL=certs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"certs.js","sourceRoot":"","sources":["../../src/commands/certs.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { Command } from 'commander';
2
+ export declare function registerExecCommand(program: Command): void;
3
+ //# sourceMappingURL=exec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exec.d.ts","sourceRoot":"","sources":["../../src/commands/exec.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAoGpC,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAoH1D"}
@@ -0,0 +1,193 @@
1
+ // Path: src/commands/exec.ts
2
+ // Exec mode - run a command with secrets as environment variables
3
+ import chalk from 'chalk';
4
+ import { spawn } from 'node:child_process';
5
+ import { isConfigured } from '../lib/config.js';
6
+ import { getSecret } from '../lib/api.js';
7
+ /**
8
+ * Parse secret mapping from CLI argument
9
+ * Formats:
10
+ * ENV_VAR=alias:secret/path -> entire secret as JSON
11
+ * ENV_VAR=alias:secret/path.key -> specific key from secret
12
+ * ENV_VAR=uuid -> entire secret as JSON
13
+ * ENV_VAR=uuid.key -> specific key from secret
14
+ */
15
+ function parseSecretMapping(mapping) {
16
+ const eqIndex = mapping.indexOf('=');
17
+ if (eqIndex === -1) {
18
+ throw new Error(`Invalid mapping format: ${mapping}. Expected: ENV_VAR=secret-id[.key]`);
19
+ }
20
+ const envVar = mapping.substring(0, eqIndex);
21
+ let secretPath = mapping.substring(eqIndex + 1);
22
+ if (!envVar || !secretPath) {
23
+ throw new Error(`Invalid mapping format: ${mapping}. Expected: ENV_VAR=secret-id[.key]`);
24
+ }
25
+ // Check if there's a key after the secret ID
26
+ // For alias format: alias:path/to/secret.key
27
+ // For UUID format: uuid.key
28
+ let key;
29
+ if (secretPath.startsWith('alias:')) {
30
+ // Handle alias:path/to/secret.key
31
+ const lastDotIndex = secretPath.lastIndexOf('.');
32
+ if (lastDotIndex > secretPath.indexOf(':') + 1) {
33
+ // There's a dot after the alias prefix
34
+ const potentialKey = secretPath.substring(lastDotIndex + 1);
35
+ // Check if this looks like a key (not a file extension or path segment)
36
+ if (potentialKey && !potentialKey.includes('/')) {
37
+ key = potentialKey;
38
+ secretPath = secretPath.substring(0, lastDotIndex);
39
+ }
40
+ }
41
+ }
42
+ else {
43
+ // Handle uuid.key or uuid
44
+ const dotIndex = secretPath.indexOf('.');
45
+ if (dotIndex !== -1) {
46
+ key = secretPath.substring(dotIndex + 1);
47
+ secretPath = secretPath.substring(0, dotIndex);
48
+ }
49
+ }
50
+ return {
51
+ envVar,
52
+ secretId: secretPath,
53
+ key,
54
+ };
55
+ }
56
+ /**
57
+ * Fetch secrets and build environment variables
58
+ */
59
+ async function buildSecretEnv(mappings) {
60
+ const env = {};
61
+ // Group by secretId to minimize API calls
62
+ const secretCache = new Map();
63
+ for (const mapping of mappings) {
64
+ let data = secretCache.get(mapping.secretId);
65
+ if (!data) {
66
+ const secret = await getSecret(mapping.secretId);
67
+ data = secret.data;
68
+ secretCache.set(mapping.secretId, data);
69
+ }
70
+ if (mapping.key) {
71
+ // Get specific key
72
+ const value = data[mapping.key];
73
+ if (value === undefined) {
74
+ throw new Error(`Key "${mapping.key}" not found in secret "${mapping.secretId}"`);
75
+ }
76
+ env[mapping.envVar] = typeof value === 'string' ? value : JSON.stringify(value);
77
+ }
78
+ else {
79
+ // Get entire secret as JSON
80
+ env[mapping.envVar] = JSON.stringify(data);
81
+ }
82
+ }
83
+ return env;
84
+ }
85
+ export function registerExecCommand(program) {
86
+ program
87
+ .command('exec')
88
+ .description('Run a command with secrets as environment variables')
89
+ .option('-s, --secret <mapping>', 'Secret mapping (ENV_VAR=secret-id[.key])', (val, acc) => {
90
+ acc.push(val);
91
+ return acc;
92
+ }, [])
93
+ .option('-o, --output <path>', 'Write secrets to env file instead of running command')
94
+ .option('--inherit', 'Inherit current environment variables (default: true)', true)
95
+ .option('--no-inherit', 'Do not inherit current environment variables')
96
+ .argument('[command...]', 'Command to execute')
97
+ .addHelpText('after', `
98
+ Examples:
99
+ # Run node with database password
100
+ zn-vault-agent exec -s DB_PASSWORD=alias:db/prod.password -- node server.js
101
+
102
+ # Multiple secrets
103
+ zn-vault-agent exec \\
104
+ -s DB_HOST=alias:db/prod.host \\
105
+ -s DB_PASSWORD=alias:db/prod.password \\
106
+ -s API_KEY=alias:api/key.value \\
107
+ -- ./start.sh
108
+
109
+ # Export to env file
110
+ zn-vault-agent exec \\
111
+ -s DB_PASSWORD=alias:db/prod.password \\
112
+ --output /tmp/secrets.env
113
+
114
+ # Get entire secret as JSON
115
+ zn-vault-agent exec -s CONFIG=alias:app/config -- node app.js
116
+ `)
117
+ .action(async (command, options) => {
118
+ if (!isConfigured()) {
119
+ console.error(chalk.red('Not configured. Run: zn-vault-agent login'));
120
+ process.exit(1);
121
+ }
122
+ if (options.secret.length === 0) {
123
+ console.error(chalk.red('At least one --secret mapping is required'));
124
+ process.exit(1);
125
+ }
126
+ // Parse mappings
127
+ let mappings;
128
+ try {
129
+ mappings = options.secret.map(parseSecretMapping);
130
+ }
131
+ catch (err) {
132
+ console.error(chalk.red('Error:'), err instanceof Error ? err.message : String(err));
133
+ process.exit(1);
134
+ }
135
+ // Fetch secrets
136
+ let secretEnv;
137
+ try {
138
+ secretEnv = await buildSecretEnv(mappings);
139
+ }
140
+ catch (err) {
141
+ console.error(chalk.red('Failed to fetch secrets:'), err instanceof Error ? err.message : String(err));
142
+ process.exit(1);
143
+ }
144
+ // If --output specified, write to file and exit
145
+ if (options.output) {
146
+ const fs = await import('node:fs');
147
+ const content = Object.entries(secretEnv)
148
+ .map(([k, v]) => `${k}="${v.replace(/"/g, '\\"')}"`)
149
+ .join('\n') + '\n';
150
+ fs.writeFileSync(options.output, content, { mode: 0o600 });
151
+ console.log(chalk.green('✓') + ` Secrets written to ${options.output}`);
152
+ return;
153
+ }
154
+ // Must have a command to run
155
+ if (command.length === 0) {
156
+ console.error(chalk.red('No command specified. Provide a command after --'));
157
+ console.error('Example: zn-vault-agent exec -s VAR=secret -- ./my-command');
158
+ process.exit(1);
159
+ }
160
+ // Build environment
161
+ const env = options.inherit
162
+ ? { ...process.env, ...secretEnv }
163
+ : secretEnv;
164
+ // Run the command
165
+ const [cmd, ...args] = command;
166
+ const child = spawn(cmd, args, {
167
+ env,
168
+ stdio: 'inherit',
169
+ shell: process.platform === 'win32',
170
+ });
171
+ // Forward signals to child
172
+ const signals = ['SIGINT', 'SIGTERM', 'SIGHUP'];
173
+ for (const signal of signals) {
174
+ process.on(signal, () => {
175
+ child.kill(signal);
176
+ });
177
+ }
178
+ // Exit with child's exit code
179
+ child.on('exit', (code, signal) => {
180
+ if (signal) {
181
+ process.kill(process.pid, signal);
182
+ }
183
+ else {
184
+ process.exit(code ?? 0);
185
+ }
186
+ });
187
+ child.on('error', (err) => {
188
+ console.error(chalk.red('Failed to start command:'), err.message);
189
+ process.exit(1);
190
+ });
191
+ });
192
+ }
193
+ //# sourceMappingURL=exec.js.map