@zincapp/znvault-cli 4.5.0 → 4.6.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.
- package/dist/commands/agent/direct/ping.d.ts.map +1 -1
- package/dist/commands/agent/direct/ping.js +3 -1
- package/dist/commands/agent/direct/ping.js.map +1 -1
- package/dist/commands/agent/direct/plugins.d.ts.map +1 -1
- package/dist/commands/agent/direct/plugins.js +3 -1
- package/dist/commands/agent/direct/plugins.js.map +1 -1
- package/dist/commands/agent/direct/update-all.d.ts.map +1 -1
- package/dist/commands/agent/direct/update-all.js +9 -6
- package/dist/commands/agent/direct/update-all.js.map +1 -1
- package/dist/commands/agent/direct/update-plugins.d.ts.map +1 -1
- package/dist/commands/agent/direct/update-plugins.js +90 -64
- package/dist/commands/agent/direct/update-plugins.js.map +1 -1
- package/dist/commands/agent/direct/update.d.ts.map +1 -1
- package/dist/commands/agent/direct/update.js +92 -65
- package/dist/commands/agent/direct/update.js.map +1 -1
- package/dist/commands/agent/direct/version.d.ts.map +1 -1
- package/dist/commands/agent/direct/version.js +3 -1
- package/dist/commands/agent/direct/version.js.map +1 -1
- package/dist/commands/agent/helpers.d.ts +1 -1
- package/dist/commands/agent/helpers.d.ts.map +1 -1
- package/dist/commands/agent/helpers.js +8 -1
- package/dist/commands/agent/helpers.js.map +1 -1
- package/dist/commands/agent/types.d.ts +6 -0
- package/dist/commands/agent/types.d.ts.map +1 -1
- package/dist/commands/host/config.d.ts.map +1 -1
- package/dist/commands/host/config.js +4 -1
- package/dist/commands/host/config.js.map +1 -1
- package/dist/commands/host/get.d.ts.map +1 -1
- package/dist/commands/host/get.js +4 -1
- package/dist/commands/host/get.js.map +1 -1
- package/dist/commands/host/helpers.d.ts +10 -0
- package/dist/commands/host/helpers.d.ts.map +1 -1
- package/dist/commands/host/helpers.js +18 -0
- package/dist/commands/host/helpers.js.map +1 -1
- package/dist/lib/client/http.d.ts.map +1 -1
- package/dist/lib/client/http.js +6 -2
- package/dist/lib/client/http.js.map +1 -1
- package/dist/lib/ssh-tunnel.d.ts +41 -0
- package/dist/lib/ssh-tunnel.d.ts.map +1 -0
- package/dist/lib/ssh-tunnel.js +144 -0
- package/dist/lib/ssh-tunnel.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
// Path: src/lib/ssh-tunnel.ts
|
|
2
|
+
/**
|
|
3
|
+
* SSH-CA-authenticated tunnel manager for reaching loopback-bound agents.
|
|
4
|
+
*
|
|
5
|
+
* Production agents bind their control/health server (:9100) to 127.0.0.1 only,
|
|
6
|
+
* so direct `http://<host>:9100` is unreachable from an operator's machine. This
|
|
7
|
+
* helper opens a local port-forward via `znvault ssh forward --print-port`
|
|
8
|
+
* (which authenticates with the vault SSH CA and honors the active profile's
|
|
9
|
+
* configured SSH user), then exposes the agent at `127.0.0.1:<localPort>`.
|
|
10
|
+
*
|
|
11
|
+
* Ported from znvault-plugin-payara's ssh-tunnel.ts so the CLI owns its own copy
|
|
12
|
+
* (the CLI must not import from a plugin package).
|
|
13
|
+
*/
|
|
14
|
+
import { spawn } from 'node:child_process';
|
|
15
|
+
const DEFAULT_REMOTE_PORT = 9100;
|
|
16
|
+
const DEFAULT_READINESS_TIMEOUT_MS = 15000;
|
|
17
|
+
const READINESS_POLL_INTERVAL_MS = 250;
|
|
18
|
+
/**
|
|
19
|
+
* Resolve the znvault binary to shell out to. The forward runs as a child of the
|
|
20
|
+
* current process, so the running binary itself is the correct one to re-invoke.
|
|
21
|
+
*/
|
|
22
|
+
function resolveZnvaultBin() {
|
|
23
|
+
const fromEnv = process.env.ZNVAULT_BIN;
|
|
24
|
+
if (fromEnv)
|
|
25
|
+
return fromEnv;
|
|
26
|
+
// process.argv[1] is the CLI entrypoint when run as `znvault ...`.
|
|
27
|
+
return process.argv[1] ?? 'znvault';
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Open an SSH-CA-authenticated local forward to `host:remotePort` via
|
|
31
|
+
* `znvault ssh forward --print-port`. Resolves once the tunnel's local port
|
|
32
|
+
* answers `GET /health`, or rejects on spawn/exit/readiness failure.
|
|
33
|
+
*
|
|
34
|
+
* The caller MUST call `close()` (a `try/finally` is the intended pattern) to
|
|
35
|
+
* tear the forward down.
|
|
36
|
+
*/
|
|
37
|
+
export async function openTunnel(host, opts = {}) {
|
|
38
|
+
const bin = resolveZnvaultBin();
|
|
39
|
+
const remotePort = opts.remotePort ?? DEFAULT_REMOTE_PORT;
|
|
40
|
+
const readinessTimeoutMs = opts.readinessTimeoutMs ?? DEFAULT_READINESS_TIMEOUT_MS;
|
|
41
|
+
const target = opts.user ? `${opts.user}@${host}` : host;
|
|
42
|
+
const args = [
|
|
43
|
+
'ssh', 'forward',
|
|
44
|
+
'--print-port',
|
|
45
|
+
'-L', `127.0.0.1:0:127.0.0.1:${remotePort}`,
|
|
46
|
+
target,
|
|
47
|
+
];
|
|
48
|
+
const child = spawn(bin, args, { stdio: ['ignore', 'pipe', 'inherit'], env: process.env });
|
|
49
|
+
const localPort = await new Promise((resolve, reject) => {
|
|
50
|
+
let buf = '';
|
|
51
|
+
let settled = false;
|
|
52
|
+
const onClose = (code) => {
|
|
53
|
+
if (!settled) {
|
|
54
|
+
settled = true;
|
|
55
|
+
reject(new Error(`ssh forward exited (code ${code ?? 'null'}) before reporting a port`));
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
const onError = (err) => {
|
|
59
|
+
if (!settled) {
|
|
60
|
+
settled = true;
|
|
61
|
+
reject(err);
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
child.on('close', onClose);
|
|
65
|
+
child.on('error', onError);
|
|
66
|
+
child.stdout?.on('data', (chunk) => {
|
|
67
|
+
if (settled)
|
|
68
|
+
return;
|
|
69
|
+
buf += chunk.toString('utf8');
|
|
70
|
+
let nl;
|
|
71
|
+
while ((nl = buf.indexOf('\n')) >= 0) {
|
|
72
|
+
const line = buf.slice(0, nl).trim();
|
|
73
|
+
buf = buf.slice(nl + 1); // consume the line
|
|
74
|
+
if (!line)
|
|
75
|
+
continue;
|
|
76
|
+
try {
|
|
77
|
+
const parsed = JSON.parse(line);
|
|
78
|
+
if (typeof parsed.localPort === 'number') {
|
|
79
|
+
settled = true;
|
|
80
|
+
child.removeListener('close', onClose);
|
|
81
|
+
child.removeListener('error', onError);
|
|
82
|
+
resolve(parsed.localPort);
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
/* not the JSON line; try the next one */
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
const close = async () => {
|
|
93
|
+
if (child.pid && !child.killed)
|
|
94
|
+
child.kill('SIGTERM');
|
|
95
|
+
// Give it a beat to die; don't hang on a lingering child.
|
|
96
|
+
await new Promise((r) => setTimeout(r, 100));
|
|
97
|
+
};
|
|
98
|
+
// App-level readiness: poll /health through the forward before returning.
|
|
99
|
+
const deadline = Date.now() + readinessTimeoutMs;
|
|
100
|
+
let lastErr = '';
|
|
101
|
+
while (Date.now() < deadline) {
|
|
102
|
+
try {
|
|
103
|
+
const res = await fetch(`http://127.0.0.1:${localPort}/health`, {
|
|
104
|
+
signal: AbortSignal.timeout(Math.max(1, Math.min(2000, deadline - Date.now()))),
|
|
105
|
+
});
|
|
106
|
+
if (res.ok)
|
|
107
|
+
return { host, localPort, pid: child.pid, close };
|
|
108
|
+
lastErr = `HTTP ${res.status}`;
|
|
109
|
+
}
|
|
110
|
+
catch (err) {
|
|
111
|
+
lastErr = err instanceof Error ? err.message : String(err);
|
|
112
|
+
}
|
|
113
|
+
await new Promise((r) => setTimeout(r, READINESS_POLL_INTERVAL_MS));
|
|
114
|
+
}
|
|
115
|
+
await close();
|
|
116
|
+
throw new Error(`Tunnel to ${host} opened (port ${localPort}) but /health never answered: ${lastErr}`);
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Whether a host is loopback (already locally reachable, no tunnel needed).
|
|
120
|
+
*/
|
|
121
|
+
export function isLoopbackHost(host) {
|
|
122
|
+
return host === '127.0.0.1' || host === 'localhost' || host === '::1';
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Run `fn` against an agent reachable at `host:port`, opening an SSH-CA tunnel
|
|
126
|
+
* first when needed and tearing it down afterward.
|
|
127
|
+
*
|
|
128
|
+
* Tunnel is skipped (direct connection used) when `tunnel` is false or the host
|
|
129
|
+
* is loopback. When tunneling, `fn` receives `127.0.0.1` + the local forward
|
|
130
|
+
* port; otherwise it receives the original host/port.
|
|
131
|
+
*/
|
|
132
|
+
export async function withAgentConnection(host, port, opts, fn) {
|
|
133
|
+
if (!opts.tunnel || isLoopbackHost(host)) {
|
|
134
|
+
return fn(host, port);
|
|
135
|
+
}
|
|
136
|
+
const tunnel = await openTunnel(host, { remotePort: port });
|
|
137
|
+
try {
|
|
138
|
+
return await fn('127.0.0.1', tunnel.localPort);
|
|
139
|
+
}
|
|
140
|
+
finally {
|
|
141
|
+
await tunnel.close();
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
//# sourceMappingURL=ssh-tunnel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ssh-tunnel.js","sourceRoot":"","sources":["../../src/lib/ssh-tunnel.ts"],"names":[],"mappings":"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"}
|