@vaultproxy/cli 0.1.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.
package/README.md ADDED
@@ -0,0 +1,63 @@
1
+ # @vaultproxy/cli
2
+
3
+ CLI for [VaultProxy](https://vaultproxy.dev) — secure API key management with proxy and fetch modes.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install -g @vaultproxy/cli
9
+ ```
10
+
11
+ ## Setup
12
+
13
+ ```bash
14
+ vp login
15
+ # Paste your proxy token (from app.vaultproxy.dev > Tokens)
16
+ ```
17
+
18
+ ## Usage
19
+
20
+ ### Fetch a key
21
+
22
+ ```bash
23
+ vp fetch openai-1
24
+ # prints: sk-real-key...
25
+ ```
26
+
27
+ ### Inject keys into your shell
28
+
29
+ ```bash
30
+ eval $(vp run openai-1=OPENAI_API_KEY)
31
+ # OPENAI_API_KEY is now set in your shell
32
+ ```
33
+
34
+ ### Inject and execute a command
35
+
36
+ ```bash
37
+ vp run railway=RAILWAY_TOKEN -- railway deploy
38
+ ```
39
+
40
+ ### Proxy mode (key never leaves VaultProxy)
41
+
42
+ ```bash
43
+ eval $(vp run openai-1=OPENAI_API_KEY --proxy)
44
+ # Sets OPENAI_API_KEY (proxy token) + OPENAI_BASE_URL (proxy endpoint)
45
+ # Your app routes through VaultProxy — real key never exposed
46
+ ```
47
+
48
+ ### Dry run (see what would be set)
49
+
50
+ ```bash
51
+ vp run openai-1=OPENAI_API_KEY --proxy --dry-run
52
+ ```
53
+
54
+ ## Environment Variables
55
+
56
+ | Variable | Description |
57
+ |----------|-------------|
58
+ | `VAULTPROXY_TOKEN` | Override stored proxy token |
59
+ | `VAULTPROXY_API_URL` | Override API URL (default: https://api.vaultproxy.dev) |
60
+
61
+ ## License
62
+
63
+ MIT
package/bin/vp.js ADDED
@@ -0,0 +1,521 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { loadConfig, saveConfig, getToken } from "../lib/config.js";
4
+ import { fetchKey, fetchProviders } from "../lib/api.js";
5
+ import { execSync } from "node:child_process";
6
+ import { createInterface } from "node:readline";
7
+
8
+ const args = process.argv.slice(2);
9
+ const command = args[0];
10
+
11
+ const HELP = `
12
+ vp — VaultProxy CLI
13
+
14
+ Commands:
15
+ vp login Save your proxy token
16
+ vp fetch <alias> Print the decrypted key for an alias
17
+ vp env <alias>=<VAR> [...] Print export statements for key mappings
18
+ vp run <alias>=<VAR> [...] Inject keys into current shell (use with eval)
19
+ vp run <alias>=<VAR> [...] -- <command>
20
+ Inject keys and run a command
21
+ vp proxy start Start the HTTPS proxy (credential injection)
22
+ vp proxy stop Stop the running proxy
23
+ vp proxy status Check if the proxy is running
24
+ vp proxy trust Print instructions to trust the CA cert
25
+
26
+ Options:
27
+ vp --help Show this help
28
+ vp --version Show version
29
+ --proxy Use proxy token + base URL instead of real key
30
+ --dry-run Show what would be set without fetching real keys
31
+
32
+ Environment:
33
+ VAULTPROXY_TOKEN Override stored token
34
+ VAULTPROXY_API_URL Override API URL (default: https://api.vaultproxy.dev)
35
+ HTTPS_PROXY Set to http://localhost:10255 when proxy is running
36
+
37
+ Examples:
38
+ vp login
39
+ vp fetch railway
40
+ eval $(vp run railway=RAILWAY_TOKEN)
41
+ vp run railway=RAILWAY_TOKEN -- railway status
42
+ eval $(vp run openai-1=OPENAI_API_KEY --proxy)
43
+ vp proxy start && export HTTPS_PROXY=http://localhost:10255
44
+ `.trim();
45
+
46
+ async function main() {
47
+ if (!command || command === "--help" || command === "-h") {
48
+ console.log(HELP);
49
+ process.exit(0);
50
+ }
51
+
52
+ if (command === "--version" || command === "-v") {
53
+ console.log("0.1.0");
54
+ process.exit(0);
55
+ }
56
+
57
+ switch (command) {
58
+ case "login":
59
+ await cmdLogin();
60
+ break;
61
+ case "fetch":
62
+ await cmdFetch();
63
+ break;
64
+ case "env":
65
+ await cmdEnv();
66
+ break;
67
+ case "run":
68
+ await cmdRun();
69
+ break;
70
+ case "proxy":
71
+ await cmdProxy();
72
+ break;
73
+ default:
74
+ console.error(`Unknown command: ${command}\nRun 'vp --help' for usage.`);
75
+ process.exit(1);
76
+ }
77
+ }
78
+
79
+ // --- login ---
80
+
81
+ async function cmdLogin() {
82
+ const cfg = loadConfig();
83
+
84
+ // Check if token provided as argument
85
+ let token = args[1];
86
+
87
+ if (!token) {
88
+ // Interactive prompt
89
+ const rl = createInterface({ input: process.stdin, output: process.stderr });
90
+ token = await new Promise((resolve) => {
91
+ rl.question("Proxy token: ", (answer) => {
92
+ rl.close();
93
+ resolve(answer.trim());
94
+ });
95
+ });
96
+ }
97
+
98
+ if (!token) {
99
+ console.error("No token provided.");
100
+ process.exit(1);
101
+ }
102
+
103
+ // Optional: custom API URL
104
+ const urlFlag = args.find((a) => a.startsWith("--api-url="));
105
+ if (urlFlag) {
106
+ cfg.api_url = urlFlag.split("=").slice(1).join("=");
107
+ }
108
+
109
+ cfg.token = token;
110
+ saveConfig(cfg);
111
+ console.error("✓ Token saved to ~/.vaultproxy/config.json");
112
+ }
113
+
114
+ // --- fetch ---
115
+
116
+ async function cmdFetch() {
117
+ const alias = args[1];
118
+ if (!alias) {
119
+ console.error("Usage: vp fetch <alias>");
120
+ process.exit(1);
121
+ }
122
+
123
+ try {
124
+ const result = await fetchKey(alias);
125
+ // Print just the key to stdout (pipeable)
126
+ process.stdout.write(result.key);
127
+ } catch (err) {
128
+ console.error(`Error: ${err.message}`);
129
+ process.exit(1);
130
+ }
131
+ }
132
+
133
+ // --- env ---
134
+
135
+ async function cmdEnv() {
136
+ const mappings = parseMappings(args.slice(1));
137
+ if (mappings.length === 0) {
138
+ console.error("Usage: vp env <alias>=<ENV_VAR> [...]");
139
+ console.error("Example: vp env railway=RAILWAY_TOKEN openai=OPENAI_API_KEY");
140
+ process.exit(1);
141
+ }
142
+
143
+ const results = await resolveAll(mappings);
144
+ for (const { envVar, key } of results) {
145
+ console.log(`export ${envVar}=${shellEscape(key)}`);
146
+ }
147
+ }
148
+
149
+ // --- run ---
150
+
151
+ async function cmdRun() {
152
+ const dashIndex = args.indexOf("--");
153
+
154
+ // Flags live before the "--" separator (or anywhere if no separator)
155
+ const flagArgs = dashIndex === -1 ? args.slice(1) : args.slice(1, dashIndex);
156
+ const isProxyMode = flagArgs.includes("--proxy");
157
+ const isDryRun = flagArgs.includes("--dry-run");
158
+
159
+ // No "--" means inject-only mode (prints export statements)
160
+ const mappingArgs = dashIndex === -1 ? args.slice(1) : args.slice(1, dashIndex);
161
+ const cmdArgs = dashIndex === -1 ? [] : args.slice(dashIndex + 1);
162
+
163
+ const mappings = parseMappings(mappingArgs);
164
+ if (mappings.length === 0) {
165
+ console.error("Usage: vp run <alias>=<ENV_VAR> [...] [-- <command>]");
166
+ console.error(" Without --: prints export statements (use with eval)");
167
+ console.error(" With --: injects keys and runs the command");
168
+ console.error(" --proxy: use proxy token + base URL injection");
169
+ console.error(" --dry-run: show what would be set without fetching real keys");
170
+ console.error("Example: eval $(vp run railway=RAILWAY_TOKEN)");
171
+ console.error("Example: vp run railway=RAILWAY_TOKEN -- railway status");
172
+ console.error("Example: eval $(vp run openai-1=OPENAI_API_KEY --proxy)");
173
+ process.exit(1);
174
+ }
175
+
176
+ // --- dry-run mode ---
177
+ if (isDryRun) {
178
+ if (isProxyMode) {
179
+ const token = getToken();
180
+ if (!token) {
181
+ console.error("Error: Not logged in. Run: vp login");
182
+ process.exit(1);
183
+ }
184
+ const cfg = loadConfig();
185
+ const proxyBase = cfg.proxy_url || "https://proxy.vaultproxy.dev";
186
+ const providers = await fetchProviders();
187
+
188
+ console.error("Would set:");
189
+ for (const { alias, envVar } of mappings) {
190
+ let keyInfo;
191
+ try {
192
+ keyInfo = await fetchKey(alias);
193
+ } catch {
194
+ keyInfo = null;
195
+ }
196
+
197
+ const maskedToken = maskValue(token);
198
+ console.error(` ${envVar}=${maskedToken} (proxy token)`);
199
+
200
+ if (keyInfo) {
201
+ const provider = providers.find((p) => p.id === keyInfo.provider);
202
+ if (provider?.base_url_env) {
203
+ const baseUrl = `${proxyBase}/proxy/${alias}`;
204
+ console.error(` ${provider.base_url_env}=${baseUrl}`);
205
+ }
206
+ }
207
+ }
208
+ } else {
209
+ // Dry-run in fetch mode: show alias->envVar without fetching real keys
210
+ console.error("Would set:");
211
+ for (const { alias, envVar } of mappings) {
212
+ console.error(` ${envVar}=<key for alias "${alias}">`);
213
+ }
214
+ }
215
+ return;
216
+ }
217
+
218
+ // --- proxy mode ---
219
+ let results;
220
+ if (isProxyMode) {
221
+ results = await resolveAllProxy(mappings);
222
+ } else {
223
+ results = await resolveAll(mappings);
224
+ }
225
+
226
+ if (cmdArgs.length === 0) {
227
+ // Inject-only mode: print export statements
228
+ for (const { envVar, key, extraEnvVar, extraValue } of results) {
229
+ console.log(`export ${envVar}=${shellEscape(key)}`);
230
+ if (extraEnvVar && extraValue) {
231
+ console.log(`export ${extraEnvVar}=${shellEscape(extraValue)}`);
232
+ }
233
+ }
234
+ return;
235
+ }
236
+
237
+ // Execute mode: inject keys and run command
238
+ const env = { ...process.env };
239
+ for (const { envVar, key, extraEnvVar, extraValue } of results) {
240
+ env[envVar] = key;
241
+ if (extraEnvVar && extraValue) {
242
+ env[extraEnvVar] = extraValue;
243
+ }
244
+ }
245
+
246
+ const cmdString = cmdArgs.join(" ");
247
+ try {
248
+ execSync(cmdString, { env, stdio: "inherit" });
249
+ } catch (err) {
250
+ process.exit(err.status || 1);
251
+ }
252
+ }
253
+
254
+ // --- proxy ---
255
+
256
+ import { existsSync, readFileSync, writeFileSync, unlinkSync } from "node:fs";
257
+ import { spawn } from "node:child_process";
258
+ import { homedir } from "node:os";
259
+ import { join } from "node:path";
260
+
261
+ const PROXY_PID_FILE = join(homedir(), ".vaultproxy", "proxy.pid");
262
+ const PROXY_PORT = process.env.VP_PROXY_PORT || "10255";
263
+
264
+ async function cmdProxy() {
265
+ const sub = args[1];
266
+
267
+ switch (sub) {
268
+ case "start":
269
+ await proxyStart();
270
+ break;
271
+ case "stop":
272
+ proxyStop();
273
+ break;
274
+ case "status":
275
+ proxyStatus();
276
+ break;
277
+ case "trust":
278
+ proxyTrust();
279
+ break;
280
+ default:
281
+ console.error("Usage: vp proxy <start|stop|status|trust>");
282
+ process.exit(1);
283
+ }
284
+ }
285
+
286
+ async function proxyStart() {
287
+ const token = getToken();
288
+ if (!token) {
289
+ console.error("Error: Not logged in. Run: vp login");
290
+ process.exit(1);
291
+ }
292
+
293
+ // Check if already running
294
+ if (existsSync(PROXY_PID_FILE)) {
295
+ const pid = parseInt(readFileSync(PROXY_PID_FILE, "utf-8").trim());
296
+ try {
297
+ process.kill(pid, 0); // Check if process exists
298
+ console.error(`Proxy already running (PID ${pid}). Use 'vp proxy stop' first.`);
299
+ process.exit(1);
300
+ } catch {
301
+ // Process not running, clean up stale PID file
302
+ unlinkSync(PROXY_PID_FILE);
303
+ }
304
+ }
305
+
306
+ // Find the proxy binary
307
+ const binaryName = "vaultproxy-proxy";
308
+ let binaryPath;
309
+
310
+ // Check common locations
311
+ const candidates = [
312
+ join(homedir(), ".vaultproxy", "bin", binaryName),
313
+ join(process.cwd(), "proxy", "target", "release", binaryName),
314
+ join(process.cwd(), binaryName),
315
+ ];
316
+
317
+ for (const p of candidates) {
318
+ if (existsSync(p)) {
319
+ binaryPath = p;
320
+ break;
321
+ }
322
+ }
323
+
324
+ // Try PATH
325
+ if (!binaryPath) {
326
+ try {
327
+ execSync(`which ${binaryName}`, { stdio: "pipe" });
328
+ binaryPath = binaryName; // It's in PATH
329
+ } catch {
330
+ // Not found
331
+ }
332
+ }
333
+
334
+ if (!binaryPath) {
335
+ console.error(`Error: ${binaryName} not found.`);
336
+ console.error("Install it from: https://github.com/Axis-Labs-HQ/vaultproxy-cloud/releases");
337
+ console.error("Or build from source: cd proxy && cargo build --release");
338
+ console.error(`Then place it in ~/.vaultproxy/bin/ or your PATH.`);
339
+ process.exit(1);
340
+ }
341
+
342
+ const cfg = loadConfig();
343
+ const apiUrl = cfg.api_url || "https://api.vaultproxy.dev";
344
+
345
+ console.error(`Starting VaultProxy HTTPS proxy on port ${PROXY_PORT}...`);
346
+
347
+ const child = spawn(binaryPath, [
348
+ "--port", PROXY_PORT,
349
+ "--control-plane-url", apiUrl,
350
+ "--proxy-token", token,
351
+ ], {
352
+ detached: true,
353
+ stdio: "ignore",
354
+ env: { ...process.env, RUST_LOG: "vaultproxy_proxy=info" },
355
+ });
356
+
357
+ child.unref();
358
+
359
+ // Save PID
360
+ writeFileSync(PROXY_PID_FILE, String(child.pid), { mode: 0o600 });
361
+
362
+ console.error(`✓ Proxy started (PID ${child.pid})`);
363
+ console.error(` Port: ${PROXY_PORT}`);
364
+ console.error(` CA cert: ~/.vaultproxy/ca/ca.crt`);
365
+ console.error("");
366
+ console.error("To use it:");
367
+ console.error(` export HTTPS_PROXY=http://localhost:${PROXY_PORT}`);
368
+ console.error("");
369
+ console.error("First time? Trust the CA cert:");
370
+ console.error(" vp proxy trust");
371
+ }
372
+
373
+ function proxyStop() {
374
+ if (!existsSync(PROXY_PID_FILE)) {
375
+ console.error("Proxy is not running.");
376
+ return;
377
+ }
378
+
379
+ const pid = parseInt(readFileSync(PROXY_PID_FILE, "utf-8").trim());
380
+ try {
381
+ process.kill(pid, "SIGTERM");
382
+ console.error(`✓ Proxy stopped (PID ${pid})`);
383
+ } catch {
384
+ console.error(`Process ${pid} not found (already stopped).`);
385
+ }
386
+ unlinkSync(PROXY_PID_FILE);
387
+ }
388
+
389
+ function proxyStatus() {
390
+ if (!existsSync(PROXY_PID_FILE)) {
391
+ console.error("Proxy is not running.");
392
+ process.exit(1);
393
+ }
394
+
395
+ const pid = parseInt(readFileSync(PROXY_PID_FILE, "utf-8").trim());
396
+ try {
397
+ process.kill(pid, 0);
398
+ console.error(`✓ Proxy is running (PID ${pid}, port ${PROXY_PORT})`);
399
+ } catch {
400
+ console.error(`✗ Proxy is not running (stale PID ${pid})`);
401
+ unlinkSync(PROXY_PID_FILE);
402
+ process.exit(1);
403
+ }
404
+ }
405
+
406
+ function proxyTrust() {
407
+ const caPath = join(homedir(), ".vaultproxy", "ca", "ca.crt");
408
+ const platform = process.platform;
409
+
410
+ console.error("Trust the VaultProxy CA certificate:\n");
411
+
412
+ if (platform === "darwin") {
413
+ console.error(" macOS:");
414
+ console.error(` sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain ${caPath}`);
415
+ } else if (platform === "linux") {
416
+ console.error(" Ubuntu/Debian:");
417
+ console.error(` sudo cp ${caPath} /usr/local/share/ca-certificates/vaultproxy-ca.crt`);
418
+ console.error(" sudo update-ca-certificates");
419
+ console.error("");
420
+ console.error(" RHEL/Fedora:");
421
+ console.error(` sudo cp ${caPath} /etc/pki/ca-trust/source/anchors/vaultproxy-ca.crt`);
422
+ console.error(" sudo update-ca-trust");
423
+ } else {
424
+ console.error(" Windows:");
425
+ console.error(` certutil -addstore -user Root ${caPath}`);
426
+ }
427
+
428
+ console.error("");
429
+ console.error(" Node.js (per-process, no system trust needed):");
430
+ console.error(` export NODE_EXTRA_CA_CERTS=${caPath}`);
431
+ console.error("");
432
+ console.error(" Python (per-process):");
433
+ console.error(` export REQUESTS_CA_BUNDLE=${caPath}`);
434
+
435
+ if (existsSync(caPath)) {
436
+ console.error(`\n CA cert location: ${caPath}`);
437
+ } else {
438
+ console.error(`\n ⚠ CA cert not found at ${caPath}`);
439
+ console.error(" Run 'vp proxy start' first to generate it.");
440
+ }
441
+ }
442
+
443
+ // --- helpers ---
444
+
445
+ function parseMappings(rawArgs) {
446
+ const mappings = [];
447
+ for (const arg of rawArgs) {
448
+ if (arg.startsWith("-")) continue; // skip flags
449
+ const eqIndex = arg.indexOf("=");
450
+ if (eqIndex === -1) {
451
+ // Shorthand: alias only, use ALIAS_KEY as env var name
452
+ mappings.push({ alias: arg, envVar: arg.toUpperCase().replace(/-/g, "_") + "_KEY" });
453
+ } else {
454
+ const alias = arg.slice(0, eqIndex);
455
+ const envVar = arg.slice(eqIndex + 1);
456
+ mappings.push({ alias, envVar });
457
+ }
458
+ }
459
+ return mappings;
460
+ }
461
+
462
+ async function resolveAll(mappings) {
463
+ const results = await Promise.all(
464
+ mappings.map(async ({ alias, envVar }) => {
465
+ const result = await fetchKey(alias);
466
+ return { alias, envVar, key: result.key };
467
+ })
468
+ );
469
+ return results;
470
+ }
471
+
472
+ async function resolveAllProxy(mappings) {
473
+ const token = getToken();
474
+ if (!token) {
475
+ throw new Error("Not logged in. Run: vp login");
476
+ }
477
+
478
+ const cfg = loadConfig();
479
+ const proxyBase = cfg.proxy_url || "https://proxy.vaultproxy.dev";
480
+ const providers = await fetchProviders();
481
+
482
+ const results = await Promise.all(
483
+ mappings.map(async ({ alias, envVar }) => {
484
+ // Always fetch key metadata to get provider info
485
+ const keyInfo = await fetchKey(alias);
486
+
487
+ // D4: warn if provider is not proxy_compatible and fall back to fetch mode
488
+ if (!keyInfo.proxy_compatible) {
489
+ console.error(
490
+ `Warning: ${keyInfo.provider} does not support proxy mode (uses request signing). Falling back to fetch mode.`
491
+ );
492
+ return { alias, envVar, key: keyInfo.key };
493
+ }
494
+
495
+ // Find provider record for base_url_env
496
+ const provider = providers.find((p) => p.id === keyInfo.provider);
497
+
498
+ const extraEnvVar = provider?.base_url_env || null;
499
+ const extraValue = extraEnvVar
500
+ ? `${proxyBase}/proxy/${alias}`
501
+ : null;
502
+
503
+ return { alias, envVar, key: token, extraEnvVar, extraValue };
504
+ })
505
+ );
506
+ return results;
507
+ }
508
+
509
+ function maskValue(value) {
510
+ if (!value || value.length <= 8) return value + "...";
511
+ return value.slice(0, 8) + "...";
512
+ }
513
+
514
+ function shellEscape(s) {
515
+ return "'" + s.replace(/'/g, "'\\''") + "'";
516
+ }
517
+
518
+ main().catch((err) => {
519
+ console.error(`Fatal: ${err.message}`);
520
+ process.exit(1);
521
+ });
package/lib/api.js ADDED
@@ -0,0 +1,50 @@
1
+ import { getApiUrl, getToken } from "./config.js";
2
+
3
+ let _providersCache = null;
4
+
5
+ export async function fetchProviders() {
6
+ if (_providersCache) return _providersCache;
7
+ try {
8
+ const url = `${getApiUrl()}/api/v1/providers`;
9
+ const res = await fetch(url);
10
+ if (!res.ok) return [];
11
+ _providersCache = await res.json();
12
+ return _providersCache;
13
+ } catch {
14
+ return [];
15
+ }
16
+ }
17
+
18
+ export async function fetchKey(alias) {
19
+ const token = getToken();
20
+ if (!token) {
21
+ throw new Error("Not logged in. Run: vp login");
22
+ }
23
+
24
+ const url = `${getApiUrl()}/internal/fetch/${encodeURIComponent(alias)}`;
25
+ const res = await fetch(url, {
26
+ headers: { Authorization: `Bearer ${token}` },
27
+ });
28
+
29
+ if (res.status === 401) throw new Error("Invalid or expired token. Run: vp login");
30
+ if (res.status === 404) throw new Error(`Key alias "${alias}" not found`);
31
+ if (res.status === 429) throw new Error("Rate limit exceeded");
32
+ if (!res.ok) throw new Error(`API error: ${res.status}`);
33
+
34
+ return res.json();
35
+ }
36
+
37
+ export async function listKeys() {
38
+ const token = getToken();
39
+ if (!token) {
40
+ throw new Error("Not logged in. Run: vp login");
41
+ }
42
+
43
+ const url = `${getApiUrl()}/internal/keys`;
44
+ const res = await fetch(url, {
45
+ headers: { Authorization: `Bearer ${token}` },
46
+ });
47
+
48
+ if (!res.ok) return [];
49
+ return res.json();
50
+ }
package/lib/config.js ADDED
@@ -0,0 +1,38 @@
1
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
2
+ import { homedir } from "node:os";
3
+ import { join } from "node:path";
4
+
5
+ const CONFIG_DIR = join(homedir(), ".vaultproxy");
6
+ const CONFIG_FILE = join(CONFIG_DIR, "config.json");
7
+
8
+ const DEFAULTS = {
9
+ api_url: "https://api.vaultproxy.dev",
10
+ proxy_url: "https://proxy.vaultproxy.dev",
11
+ };
12
+
13
+ export function loadConfig() {
14
+ if (!existsSync(CONFIG_FILE)) return { ...DEFAULTS };
15
+ try {
16
+ const raw = readFileSync(CONFIG_FILE, "utf-8");
17
+ return { ...DEFAULTS, ...JSON.parse(raw) };
18
+ } catch {
19
+ return { ...DEFAULTS };
20
+ }
21
+ }
22
+
23
+ export function saveConfig(config) {
24
+ if (!existsSync(CONFIG_DIR)) mkdirSync(CONFIG_DIR, { recursive: true });
25
+ writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2) + "\n", {
26
+ mode: 0o600,
27
+ });
28
+ }
29
+
30
+ export function getToken() {
31
+ const cfg = loadConfig();
32
+ // Env var takes precedence over config file
33
+ return process.env.VAULTPROXY_TOKEN || cfg.token || null;
34
+ }
35
+
36
+ export function getApiUrl() {
37
+ return process.env.VAULTPROXY_API_URL || loadConfig().api_url;
38
+ }
package/package.json ADDED
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "@vaultproxy/cli",
3
+ "version": "0.1.0",
4
+ "description": "VaultProxy CLI — fetch, inject, and proxy API keys",
5
+ "bin": {
6
+ "vp": "./bin/vp.js"
7
+ },
8
+ "type": "module",
9
+ "license": "MIT",
10
+ "engines": {
11
+ "node": ">=18"
12
+ },
13
+ "files": [
14
+ "bin/",
15
+ "lib/"
16
+ ],
17
+ "repository": {
18
+ "type": "git",
19
+ "url": "https://github.com/Axis-Labs-HQ/vaultproxy-cloud",
20
+ "directory": "cli"
21
+ },
22
+ "homepage": "https://vaultproxy.dev",
23
+ "keywords": [
24
+ "api-keys",
25
+ "secrets",
26
+ "proxy",
27
+ "rotation",
28
+ "vault",
29
+ "security",
30
+ "cli"
31
+ ],
32
+ "publishConfig": {
33
+ "access": "public"
34
+ }
35
+ }