@zincapp/znvault-cli 4.4.0 → 4.5.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/dist/commands/kmip/clients.d.ts +4 -0
- package/dist/commands/kmip/clients.d.ts.map +1 -1
- package/dist/commands/kmip/clients.js +37 -0
- package/dist/commands/kmip/clients.js.map +1 -1
- package/dist/commands/kmip/index.d.ts.map +1 -1
- package/dist/commands/kmip/index.js +7 -1
- package/dist/commands/kmip/index.js.map +1 -1
- package/dist/commands/kmip/types.d.ts +1 -0
- package/dist/commands/kmip/types.d.ts.map +1 -1
- package/dist/commands/ssh/connect.d.ts +22 -0
- package/dist/commands/ssh/connect.d.ts.map +1 -1
- package/dist/commands/ssh/connect.js +90 -163
- package/dist/commands/ssh/connect.js.map +1 -1
- package/dist/commands/ssh/forward.d.ts +49 -0
- package/dist/commands/ssh/forward.d.ts.map +1 -0
- package/dist/commands/ssh/forward.js +151 -0
- package/dist/commands/ssh/forward.js.map +1 -0
- package/dist/commands/ssh/index.d.ts.map +1 -1
- package/dist/commands/ssh/index.js +9 -1
- package/dist/commands/ssh/index.js.map +1 -1
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
interface CreateOptions {
|
|
2
2
|
description?: string;
|
|
3
3
|
outputDir?: string;
|
|
4
|
+
allowedCidrs?: string;
|
|
4
5
|
json?: boolean;
|
|
5
6
|
}
|
|
6
7
|
export declare function createClient(name: string, options: CreateOptions): Promise<void>;
|
|
7
8
|
export declare function listClients(options: {
|
|
8
9
|
json?: boolean;
|
|
9
10
|
}): Promise<void>;
|
|
11
|
+
export declare function setSourceCidrs(id: string, cidrs: string, options: {
|
|
12
|
+
json?: boolean;
|
|
13
|
+
}): Promise<void>;
|
|
10
14
|
export declare function revokeClient(id: string, options: {
|
|
11
15
|
json?: boolean;
|
|
12
16
|
}): Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"clients.d.ts","sourceRoot":"","sources":["../../../src/commands/kmip/clients.ts"],"names":[],"mappings":"AASA,UAAU,aAAa;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;
|
|
1
|
+
{"version":3,"file":"clients.d.ts","sourceRoot":"","sources":["../../../src/commands/kmip/clients.ts"],"names":[],"mappings":"AASA,UAAU,aAAa;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAWD,wBAAsB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAoCtF;AAED,wBAAsB,WAAW,CAAC,OAAO,EAAE;IAAE,IAAI,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CA6B5E;AAED,wBAAsB,cAAc,CAClC,EAAE,EAAE,MAAM,EACV,KAAK,EAAE,MAAM,EACb,OAAO,EAAE;IAAE,IAAI,CAAC,EAAE,OAAO,CAAA;CAAE,GAC1B,OAAO,CAAC,IAAI,CAAC,CAuBf;AAED,wBAAsB,YAAY,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE;IAAE,IAAI,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAezF"}
|
|
@@ -4,12 +4,23 @@ import fs from 'fs';
|
|
|
4
4
|
import path from 'path';
|
|
5
5
|
import { client } from '../../lib/client.js';
|
|
6
6
|
import * as output from '../../lib/output.js';
|
|
7
|
+
/** Parse a comma-separated CIDR list into a trimmed string[] (empty if unset). */
|
|
8
|
+
function parseCidrList(raw) {
|
|
9
|
+
if (raw === undefined)
|
|
10
|
+
return [];
|
|
11
|
+
return raw
|
|
12
|
+
.split(',')
|
|
13
|
+
.map((s) => s.trim())
|
|
14
|
+
.filter((s) => s.length > 0);
|
|
15
|
+
}
|
|
7
16
|
export async function createClient(name, options) {
|
|
8
17
|
const spinner = output.spinner(`Creating KMIP client '${name}'...`).start();
|
|
9
18
|
try {
|
|
19
|
+
const allowedSourceCidrs = parseCidrList(options.allowedCidrs);
|
|
10
20
|
const response = await client.post('/v1/kmip/clients', {
|
|
11
21
|
name,
|
|
12
22
|
description: options.description,
|
|
23
|
+
...(allowedSourceCidrs.length > 0 ? { allowedSourceCidrs } : {}),
|
|
13
24
|
});
|
|
14
25
|
spinner.stop();
|
|
15
26
|
if (options.json) {
|
|
@@ -64,6 +75,32 @@ export async function listClients(options) {
|
|
|
64
75
|
process.exit(1);
|
|
65
76
|
}
|
|
66
77
|
}
|
|
78
|
+
export async function setSourceCidrs(id, cidrs, options) {
|
|
79
|
+
const allowedSourceCidrs = parseCidrList(cidrs);
|
|
80
|
+
const verb = allowedSourceCidrs.length > 0 ? 'Setting' : 'Clearing';
|
|
81
|
+
const spinner = output.spinner(`${verb} source-IP allowlist for KMIP client ${id}...`).start();
|
|
82
|
+
try {
|
|
83
|
+
const response = await client.put(`/v1/kmip/clients/${id}/source-cidrs`, {
|
|
84
|
+
allowedSourceCidrs,
|
|
85
|
+
});
|
|
86
|
+
spinner.stop();
|
|
87
|
+
if (options.json) {
|
|
88
|
+
output.json(response);
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
if (allowedSourceCidrs.length > 0) {
|
|
92
|
+
output.success(`Source-IP allowlist set for '${response.name ?? id}': ${allowedSourceCidrs.join(', ')}`);
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
output.success(`Source-IP allowlist cleared for '${response.name ?? id}' (no restriction)`);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
catch (err) {
|
|
99
|
+
spinner.fail('Failed to set KMIP client source-IP allowlist');
|
|
100
|
+
output.error(err instanceof Error ? err.message : String(err));
|
|
101
|
+
process.exit(1);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
67
104
|
export async function revokeClient(id, options) {
|
|
68
105
|
const spinner = output.spinner(`Revoking KMIP client ${id}...`).start();
|
|
69
106
|
try {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"clients.js","sourceRoot":"","sources":["../../../src/commands/kmip/clients.ts"],"names":[],"mappings":"AAAA,qCAAqC;AACrC,mCAAmC;AAEnC,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAC7C,OAAO,KAAK,MAAM,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"clients.js","sourceRoot":"","sources":["../../../src/commands/kmip/clients.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/kmip/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,OAAO,EAAE,MAAM,WAAW,CAAC;AAKzC,cAAc,YAAY,CAAC;AAE3B,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/kmip/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,OAAO,EAAE,MAAM,WAAW,CAAC;AAKzC,cAAc,YAAY,CAAC;AAE3B,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAsD3D;AAED,+FAA+F;AAC/F,wBAAgB,8BAA8B,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI,CASpE"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// Path: src/commands/kmip/index.ts
|
|
2
2
|
// `znvault kmip` command registration.
|
|
3
|
-
import { createClient, listClients, revokeClient } from './clients.js';
|
|
3
|
+
import { createClient, listClients, revokeClient, setSourceCidrs } from './clients.js';
|
|
4
4
|
import { listObjects, getStatus } from './objects.js';
|
|
5
5
|
import { enableKmip, reissueServerCert } from './admin.js';
|
|
6
6
|
export * from './types.js';
|
|
@@ -34,9 +34,15 @@ Examples:
|
|
|
34
34
|
.description('Create a KMIP client and download its certificate bundle')
|
|
35
35
|
.option('--description <text>', 'Optional description')
|
|
36
36
|
.option('--output-dir <dir>', 'Directory to write client.key/client.crt/ca.crt (default: kmip-<name>)')
|
|
37
|
+
.option('--allowed-cidrs <cidrs>', 'Comma-separated source-IP allowlist (e.g. "192.168.50.4/32"). Defense-in-depth on top of mTLS; empty = no restriction')
|
|
37
38
|
.option('--json', 'Output as JSON (includes the private key)')
|
|
38
39
|
.action(createClient);
|
|
39
40
|
clientCmd.command('list').description('List KMIP clients').option('--json', 'Output as JSON').action(listClients);
|
|
41
|
+
clientCmd
|
|
42
|
+
.command('set-cidrs <id> <cidrs>')
|
|
43
|
+
.description('Set a client source-IP allowlist (comma-separated CIDRs; empty string clears it)')
|
|
44
|
+
.option('--json', 'Output as JSON')
|
|
45
|
+
.action(setSourceCidrs);
|
|
40
46
|
clientCmd
|
|
41
47
|
.command('revoke <id>')
|
|
42
48
|
.description('Revoke a KMIP client')
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/commands/kmip/index.ts"],"names":[],"mappings":"AAAA,mCAAmC;AACnC,uCAAuC;AAGvC,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/commands/kmip/index.ts"],"names":[],"mappings":"AAAA,mCAAmC;AACnC,uCAAuC;AAGvC,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACvF,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACtD,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAE3D,cAAc,YAAY,CAAC;AAE3B,MAAM,UAAU,oBAAoB,CAAC,OAAgB;IACnD,MAAM,IAAI,GAAG,OAAO;SACjB,OAAO,CAAC,MAAM,CAAC;SACf,WAAW,CAAC,wDAAwD,CAAC;SACrE,WAAW,CAAC,OAAO,EAAE;;;;;;;;;;;;;;;;;;CAkBzB,CAAC,CAAC;IAED,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,WAAW,CAAC,0BAA0B,CAAC,CAAC,MAAM,CAAC,QAAQ,EAAE,gBAAgB,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IAEpH,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,WAAW,CAAC,qBAAqB,CAAC,CAAC;IAC5E,SAAS;SACN,OAAO,CAAC,eAAe,CAAC;SACxB,WAAW,CAAC,0DAA0D,CAAC;SACvE,MAAM,CAAC,sBAAsB,EAAE,sBAAsB,CAAC;SACtD,MAAM,CAAC,oBAAoB,EAAE,wEAAwE,CAAC;SACtG,MAAM,CACL,yBAAyB,EACzB,uHAAuH,CACxH;SACA,MAAM,CAAC,QAAQ,EAAE,2CAA2C,CAAC;SAC7D,MAAM,CAAC,YAAY,CAAC,CAAC;IACxB,SAAS,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,mBAAmB,CAAC,CAAC,MAAM,CAAC,QAAQ,EAAE,gBAAgB,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;IAClH,SAAS;SACN,OAAO,CAAC,wBAAwB,CAAC;SACjC,WAAW,CAAC,kFAAkF,CAAC;SAC/F,MAAM,CAAC,QAAQ,EAAE,gBAAgB,CAAC;SAClC,MAAM,CAAC,cAAc,CAAC,CAAC;IAC1B,SAAS;SACN,OAAO,CAAC,aAAa,CAAC;SACtB,WAAW,CAAC,sBAAsB,CAAC;SACnC,MAAM,CAAC,QAAQ,EAAE,gBAAgB,CAAC;SAClC,MAAM,CAAC,YAAY,CAAC,CAAC;IAExB,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,WAAW,CAAC,8CAA8C,CAAC,CAAC;IACrG,SAAS,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,mBAAmB,CAAC,CAAC,MAAM,CAAC,QAAQ,EAAE,gBAAgB,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;IAElH,OAAO;AACT,CAAC;AAED,+FAA+F;AAC/F,MAAM,UAAU,8BAA8B,CAAC,MAAe;IAC5D,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,4BAA4B,CAAC,CAAC;IAC9E,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,WAAW,CAAC,4CAA4C,CAAC,CAAC,MAAM,CAAC,QAAQ,EAAE,gBAAgB,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;IACvI,IAAI;SACD,OAAO,CAAC,qBAAqB,CAAC;SAC9B,WAAW,CAAC,kEAAkE,CAAC;SAC/E,MAAM,CAAC,WAAW,EAAE,8BAA8B,CAAC;SACnD,MAAM,CAAC,QAAQ,EAAE,gBAAgB,CAAC;SAClC,MAAM,CAAC,iBAAiB,CAAC,CAAC;AAC/B,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/commands/kmip/types.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/commands/kmip/types.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;CAC/B;AAED,MAAM,WAAW,gBAAgB;IAC/B,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,wBAAyB,SAAQ,UAAU;IAC1D,MAAM,EAAE,gBAAgB,CAAC;CAC1B;AAED,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,sBAAsB,EAAE,MAAM,CAAC;IAC/B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,SAAS,EAAE,OAAO,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IACjE,cAAc,EAAE,OAAO,CAAC;IACxB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,sBAAsB,EAAE,MAAM,GAAG,IAAI,CAAC;CACvC;AAED,MAAM,WAAW,iBAAiB,CAAC,CAAC;IAClC,KAAK,EAAE,CAAC,EAAE,CAAC;IACX,UAAU,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC;CAChF"}
|
|
@@ -3,6 +3,28 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import type { Command } from 'commander';
|
|
5
5
|
import type { ConnectOptions } from './types.js';
|
|
6
|
+
/**
|
|
7
|
+
* Result of resolving + signing an SSH-CA connection. Contains everything
|
|
8
|
+
* needed to build any ssh invocation (interactive, forward, exec).
|
|
9
|
+
*/
|
|
10
|
+
export interface SignedSshBase {
|
|
11
|
+
keyPath: string;
|
|
12
|
+
certPath: string;
|
|
13
|
+
user?: string;
|
|
14
|
+
host: string;
|
|
15
|
+
port: string;
|
|
16
|
+
/** ['-i', key, ('-p', port)?, '-o', `CertificateFile=cert`] — ready to prefix any ssh args */
|
|
17
|
+
baseSshArgs: string[];
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Resolve the SSH key, ensure a valid vault-CA certificate (auto-signing if
|
|
21
|
+
* needed), and return the destination parts + base ssh args. No spawning,
|
|
22
|
+
* no process.exit, no stdio side effects — safe to call from any command.
|
|
23
|
+
*
|
|
24
|
+
* Mirrors the key-resolution + sign logic previously inline in executeConnect,
|
|
25
|
+
* so `ssh connect` and `ssh forward` share one code path.
|
|
26
|
+
*/
|
|
27
|
+
export declare function ensureSignedSshBase(destination: string, options: ConnectOptions): Promise<SignedSshBase>;
|
|
6
28
|
/**
|
|
7
29
|
* Execute SSH connection with certificate authentication
|
|
8
30
|
* Extracted for reuse by both `ssh connect` and `ssh <destination>` shortcuts
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"connect.d.ts","sourceRoot":"","sources":["../../../src/commands/ssh/connect.ts"],"names":[],"mappings":"AAEA;;GAEG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAIzC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AASjD;;;GAGG;AACH,wBAAsB,cAAc,CAClC,WAAW,EAAE,MAAM,EACnB,aAAa,EAAE,MAAM,EAAE,EACvB,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"connect.d.ts","sourceRoot":"","sources":["../../../src/commands/ssh/connect.ts"],"names":[],"mappings":"AAEA;;GAEG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAIzC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AASjD;;;GAGG;AACH,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,8FAA8F;IAC9F,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;AAED;;;;;;;GAOG;AACH,wBAAsB,mBAAmB,CACvC,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,aAAa,CAAC,CA8DxB;AAED;;;GAGG;AACH,wBAAsB,cAAc,CAClC,WAAW,EAAE,MAAM,EACnB,aAAa,EAAE,MAAM,EAAE,EACvB,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,IAAI,CAAC,CA8Cf;AAED,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI,CAiB5D"}
|
|
@@ -4,205 +4,132 @@ import { getCurrentProfile } from '../../lib/config.js';
|
|
|
4
4
|
import { getDefaultKeyPath, getCertificatePath, isCertificateValid, signCertificate, } from './helpers.js';
|
|
5
5
|
import { resolveBookmark } from './bookmark.js';
|
|
6
6
|
/**
|
|
7
|
-
*
|
|
8
|
-
*
|
|
7
|
+
* Resolve the SSH key, ensure a valid vault-CA certificate (auto-signing if
|
|
8
|
+
* needed), and return the destination parts + base ssh args. No spawning,
|
|
9
|
+
* no process.exit, no stdio side effects — safe to call from any command.
|
|
10
|
+
*
|
|
11
|
+
* Mirrors the key-resolution + sign logic previously inline in executeConnect,
|
|
12
|
+
* so `ssh connect` and `ssh forward` share one code path.
|
|
9
13
|
*/
|
|
10
|
-
export async function
|
|
14
|
+
export async function ensureSignedSshBase(destination, options) {
|
|
11
15
|
const fs = await import('fs');
|
|
12
16
|
const path = await import('path');
|
|
13
|
-
const { spawn } = await import('child_process');
|
|
14
|
-
// Get profile config for defaults
|
|
15
17
|
const profile = getCurrentProfile();
|
|
16
|
-
// Resolve destination: could be a bookmark, user@host, or just host
|
|
17
18
|
let user;
|
|
18
19
|
let host;
|
|
19
20
|
let port = options.port ?? '22';
|
|
20
21
|
let identityOverride = options.identity;
|
|
21
22
|
let principalsOverride = options.principals;
|
|
22
|
-
// Check if destination is a bookmark
|
|
23
23
|
const bookmark = resolveBookmark(destination);
|
|
24
24
|
if (bookmark) {
|
|
25
25
|
host = bookmark.host;
|
|
26
26
|
user = bookmark.user;
|
|
27
|
-
if (bookmark.port)
|
|
27
|
+
if (bookmark.port)
|
|
28
28
|
port = bookmark.port.toString();
|
|
29
|
-
|
|
30
|
-
if (bookmark.identity) {
|
|
29
|
+
if (bookmark.identity)
|
|
31
30
|
identityOverride = bookmark.identity;
|
|
32
|
-
}
|
|
33
31
|
if (bookmark.principals && !options.principals) {
|
|
34
32
|
principalsOverride = bookmark.principals.join(',');
|
|
35
33
|
}
|
|
36
|
-
if (options.verbose) {
|
|
37
|
-
output.info(`Using bookmark '${destination}' → ${bookmark.host}`);
|
|
38
|
-
}
|
|
39
34
|
}
|
|
40
35
|
else if (destination.includes('@')) {
|
|
41
36
|
const parts = destination.split('@');
|
|
42
37
|
user = parts[0];
|
|
43
|
-
host = parts.slice(1).join('@');
|
|
38
|
+
host = parts.slice(1).join('@');
|
|
44
39
|
}
|
|
45
40
|
else {
|
|
46
41
|
host = destination;
|
|
47
|
-
|
|
48
|
-
if (profile.sshUser) {
|
|
42
|
+
if (profile.sshUser)
|
|
49
43
|
user = profile.sshUser;
|
|
50
|
-
}
|
|
51
44
|
}
|
|
52
|
-
|
|
53
|
-
if (options.port && options.port !== '22') {
|
|
45
|
+
if (options.port && options.port !== '22')
|
|
54
46
|
port = options.port;
|
|
47
|
+
// Resolve key
|
|
48
|
+
let keyPath;
|
|
49
|
+
if (identityOverride) {
|
|
50
|
+
keyPath = path.resolve(identityOverride.replace(/^~/, process.env.HOME ?? ''));
|
|
51
|
+
if (!fs.existsSync(keyPath))
|
|
52
|
+
throw new Error(`SSH key not found: ${keyPath}`);
|
|
53
|
+
}
|
|
54
|
+
else if (profile.sshIdentity && fs.existsSync(profile.sshIdentity)) {
|
|
55
|
+
keyPath = profile.sshIdentity;
|
|
55
56
|
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
57
|
+
else {
|
|
58
|
+
const defaultKey = await getDefaultKeyPath();
|
|
59
|
+
if (!defaultKey) {
|
|
60
|
+
throw new Error('No SSH key found in ~/.ssh/ — generate one with: ssh-keygen -t ed25519');
|
|
59
61
|
}
|
|
60
|
-
|
|
62
|
+
keyPath = defaultKey;
|
|
63
|
+
}
|
|
64
|
+
const pubKeyPath = `${keyPath}.pub`;
|
|
65
|
+
if (!fs.existsSync(pubKeyPath))
|
|
66
|
+
throw new Error(`Public key not found: ${pubKeyPath}`);
|
|
67
|
+
// Ensure cert
|
|
68
|
+
const certPath = await getCertificatePath(keyPath);
|
|
69
|
+
const certStatus = await isCertificateValid(certPath);
|
|
70
|
+
if (options.forceSign || !certStatus.valid) {
|
|
71
|
+
await signCertificate(pubKeyPath, certPath, principalsOverride, options.ttl, options.tenant);
|
|
72
|
+
}
|
|
73
|
+
// Build base ssh args (identity + cert + optional port)
|
|
74
|
+
const baseSshArgs = ['-i', keyPath];
|
|
75
|
+
if (port && port !== '22')
|
|
76
|
+
baseSshArgs.push('-p', port);
|
|
77
|
+
baseSshArgs.push('-o', `CertificateFile=${certPath}`);
|
|
78
|
+
return { keyPath, certPath, user, host, port, baseSshArgs };
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Execute SSH connection with certificate authentication
|
|
82
|
+
* Extracted for reuse by both `ssh connect` and `ssh <destination>` shortcuts
|
|
83
|
+
*/
|
|
84
|
+
export async function executeConnect(destination, remoteCommand, options) {
|
|
85
|
+
const { spawn } = await import('child_process');
|
|
86
|
+
const verbose = (msg) => { if (options.verbose)
|
|
87
|
+
output.info(msg); };
|
|
88
|
+
let base;
|
|
61
89
|
try {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
output.error(`SSH key not found: ${keyPath}`);
|
|
68
|
-
process.exit(1);
|
|
69
|
-
}
|
|
70
|
-
verbose(`Using specified key: ${keyPath}`);
|
|
71
|
-
}
|
|
72
|
-
else if (profile.sshIdentity && fs.existsSync(profile.sshIdentity)) {
|
|
73
|
-
// Use configured identity from profile
|
|
74
|
-
keyPath = profile.sshIdentity;
|
|
75
|
-
verbose(`Using configured key: ${keyPath}`);
|
|
76
|
-
}
|
|
77
|
-
else {
|
|
78
|
-
const defaultKey = await getDefaultKeyPath();
|
|
79
|
-
if (!defaultKey) {
|
|
80
|
-
output.error('No SSH key found in ~/.ssh/');
|
|
81
|
-
output.info('Generate one with: ssh-keygen -t ed25519');
|
|
82
|
-
output.info('Or specify a key with: znvault ssh -i /path/to/key user@host');
|
|
83
|
-
process.exit(1);
|
|
84
|
-
}
|
|
85
|
-
keyPath = defaultKey;
|
|
86
|
-
verbose(`Using default key: ${keyPath}`);
|
|
87
|
-
}
|
|
88
|
-
const pubKeyPath = `${keyPath}.pub`;
|
|
89
|
-
if (!fs.existsSync(pubKeyPath)) {
|
|
90
|
-
output.error(`Public key not found: ${pubKeyPath}`);
|
|
91
|
-
process.exit(1);
|
|
92
|
-
}
|
|
93
|
-
// Step 2: Check certificate validity
|
|
94
|
-
const certPath = await getCertificatePath(keyPath);
|
|
95
|
-
verbose(`Certificate path: ${certPath}`);
|
|
96
|
-
const certStatus = await isCertificateValid(certPath);
|
|
97
|
-
const needsSign = options.forceSign || !certStatus.valid;
|
|
98
|
-
if (options.verbose && !certStatus.valid) {
|
|
99
|
-
output.warn(`Certificate needs signing: ${certStatus.reason}`);
|
|
100
|
-
}
|
|
101
|
-
else if (options.verbose && certStatus.valid) {
|
|
102
|
-
output.success('Certificate is valid');
|
|
103
|
-
}
|
|
104
|
-
// Step 3: Sign if needed
|
|
105
|
-
if (needsSign) {
|
|
106
|
-
const spinner = output.spinner('Signing certificate...').start();
|
|
107
|
-
try {
|
|
108
|
-
await signCertificate(pubKeyPath, certPath, principalsOverride, options.ttl, options.tenant);
|
|
109
|
-
spinner.succeed('Certificate signed');
|
|
110
|
-
// Show certificate info
|
|
111
|
-
if (options.verbose) {
|
|
112
|
-
const { execSync } = await import('child_process');
|
|
113
|
-
try {
|
|
114
|
-
const certInfo = execSync(`ssh-keygen -L -f "${certPath}"`, { encoding: 'utf8' });
|
|
115
|
-
const principalsMatch = certInfo.match(/Principals:\s*([\s\S]*?)(?=\s+Critical Options:)/);
|
|
116
|
-
const validMatch = certInfo.match(/Valid:\s+from\s+(\S+)\s+to\s+(\S+)/);
|
|
117
|
-
if (principalsMatch) {
|
|
118
|
-
const principals = principalsMatch[1].trim().split('\n').map(p => p.trim()).filter(Boolean);
|
|
119
|
-
output.info(`Principals: ${principals.join(', ')}`);
|
|
120
|
-
}
|
|
121
|
-
if (validMatch) {
|
|
122
|
-
output.info(`Valid until: ${validMatch[2]}`);
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
catch {
|
|
126
|
-
// Ignore cert inspection errors
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
catch (err) {
|
|
131
|
-
spinner.fail('Failed to sign certificate');
|
|
132
|
-
output.error(err instanceof Error ? err.message : String(err));
|
|
133
|
-
process.exit(1);
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
else if (!options.verbose) {
|
|
137
|
-
// In non-verbose mode, just mention we're using existing cert
|
|
138
|
-
output.info('Using existing valid certificate');
|
|
139
|
-
}
|
|
140
|
-
// Step 4: Build SSH command
|
|
141
|
-
const sshArgs = [];
|
|
142
|
-
// Add identity file (this tells SSH to use our key + cert)
|
|
143
|
-
sshArgs.push('-i', keyPath);
|
|
144
|
-
// Add port if not default
|
|
145
|
-
if (port && port !== '22') {
|
|
146
|
-
sshArgs.push('-p', port);
|
|
147
|
-
}
|
|
148
|
-
// Add TTY allocation flags
|
|
149
|
-
if (options.t) {
|
|
150
|
-
sshArgs.push('-t');
|
|
151
|
-
}
|
|
152
|
-
else if (options.T) {
|
|
153
|
-
sshArgs.push('-T');
|
|
154
|
-
}
|
|
155
|
-
// Explicitly tell SSH to use the certificate
|
|
156
|
-
sshArgs.push('-o', `CertificateFile=${certPath}`);
|
|
157
|
-
// Add destination
|
|
158
|
-
if (user) {
|
|
159
|
-
sshArgs.push(`${user}@${host}`);
|
|
160
|
-
}
|
|
161
|
-
else {
|
|
162
|
-
sshArgs.push(host);
|
|
163
|
-
}
|
|
164
|
-
// Add remote command if specified
|
|
165
|
-
if (remoteCommand && remoteCommand.length > 0) {
|
|
166
|
-
sshArgs.push(...remoteCommand);
|
|
167
|
-
}
|
|
168
|
-
// Step 5: Execute SSH
|
|
169
|
-
if (options.dryRun) {
|
|
170
|
-
output.section('Dry Run');
|
|
171
|
-
output.keyValue({
|
|
172
|
-
'Key': keyPath,
|
|
173
|
-
'Certificate': certPath,
|
|
174
|
-
'Host': host,
|
|
175
|
-
'User': user ?? '(default)',
|
|
176
|
-
'Port': port,
|
|
177
|
-
'Principals': principalsOverride ?? '(from mapping)',
|
|
178
|
-
'Command': remoteCommand.length > 0 ? remoteCommand.join(' ') : '(interactive shell)',
|
|
179
|
-
});
|
|
180
|
-
console.log();
|
|
181
|
-
output.info(`Would execute: ssh ${sshArgs.join(' ')}`);
|
|
182
|
-
return;
|
|
183
|
-
}
|
|
184
|
-
verbose(`Executing: ssh ${sshArgs.join(' ')}`);
|
|
185
|
-
// Only print empty line for interactive sessions
|
|
186
|
-
if (remoteCommand.length === 0) {
|
|
187
|
-
console.log();
|
|
188
|
-
}
|
|
189
|
-
// Spawn SSH with stdio inherited (interactive session)
|
|
190
|
-
const sshProcess = spawn('ssh', sshArgs, {
|
|
191
|
-
stdio: 'inherit',
|
|
192
|
-
env: process.env,
|
|
193
|
-
});
|
|
194
|
-
sshProcess.on('close', (code) => {
|
|
195
|
-
process.exit(code ?? 0);
|
|
196
|
-
});
|
|
197
|
-
sshProcess.on('error', (err) => {
|
|
198
|
-
output.error(`Failed to start SSH: ${err.message}`);
|
|
199
|
-
process.exit(1);
|
|
200
|
-
});
|
|
90
|
+
if (options.verbose)
|
|
91
|
+
output.info('Resolving SSH certificate...');
|
|
92
|
+
base = await ensureSignedSshBase(destination, options);
|
|
93
|
+
if (options.verbose)
|
|
94
|
+
output.success('Certificate ready');
|
|
201
95
|
}
|
|
202
96
|
catch (err) {
|
|
203
97
|
output.error(err instanceof Error ? err.message : String(err));
|
|
204
98
|
process.exit(1);
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
// Build the interactive ssh args from the shared base
|
|
102
|
+
const sshArgs = [...base.baseSshArgs];
|
|
103
|
+
if (options.t)
|
|
104
|
+
sshArgs.push('-t');
|
|
105
|
+
else if (options.T)
|
|
106
|
+
sshArgs.push('-T');
|
|
107
|
+
sshArgs.push(base.user ? `${base.user}@${base.host}` : base.host);
|
|
108
|
+
if (remoteCommand && remoteCommand.length > 0)
|
|
109
|
+
sshArgs.push(...remoteCommand);
|
|
110
|
+
if (options.dryRun) {
|
|
111
|
+
output.section('Dry Run');
|
|
112
|
+
output.keyValue({
|
|
113
|
+
'Key': base.keyPath,
|
|
114
|
+
'Certificate': base.certPath,
|
|
115
|
+
'Host': base.host,
|
|
116
|
+
'User': base.user ?? '(default)',
|
|
117
|
+
'Port': base.port,
|
|
118
|
+
'Command': remoteCommand.length > 0 ? remoteCommand.join(' ') : '(interactive shell)',
|
|
119
|
+
});
|
|
120
|
+
console.log();
|
|
121
|
+
output.info(`Would execute: ssh ${sshArgs.join(' ')}`);
|
|
122
|
+
return;
|
|
205
123
|
}
|
|
124
|
+
verbose(`Executing: ssh ${sshArgs.join(' ')}`);
|
|
125
|
+
if (remoteCommand.length === 0)
|
|
126
|
+
console.log();
|
|
127
|
+
const sshProcess = spawn('ssh', sshArgs, { stdio: 'inherit', env: process.env });
|
|
128
|
+
sshProcess.on('close', (code) => process.exit(code ?? 0));
|
|
129
|
+
sshProcess.on('error', (err) => {
|
|
130
|
+
output.error(`Failed to start SSH: ${err.message}`);
|
|
131
|
+
process.exit(1);
|
|
132
|
+
});
|
|
206
133
|
}
|
|
207
134
|
export function registerConnectCommand(parent) {
|
|
208
135
|
parent
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"connect.js","sourceRoot":"","sources":["../../../src/commands/ssh/connect.ts"],"names":[],"mappings":"AAAA,oCAAoC;AAQpC,OAAO,KAAK,MAAM,MAAM,qBAAqB,CAAC;AAC9C,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAExD,OAAO,EACL,iBAAiB,EACjB,kBAAkB,EAClB,kBAAkB,EAClB,eAAe,GAChB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"connect.js","sourceRoot":"","sources":["../../../src/commands/ssh/connect.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SSH local port-forward with vault-CA certificate authentication.
|
|
3
|
+
*
|
|
4
|
+
* `znvault ssh forward -L 127.0.0.1:<lport>:<rhost>:<rport> <destination>`
|
|
5
|
+
* opens `ssh -N -L ...` using an auto-signed vault SSH certificate. The
|
|
6
|
+
* `--print-port` machine mode binds an OS-chosen local port and prints a
|
|
7
|
+
* single JSON line so callers (e.g. the payara deploy plugin) can consume it.
|
|
8
|
+
*/
|
|
9
|
+
import type { Command } from 'commander';
|
|
10
|
+
import type { ConnectOptions } from './types.js';
|
|
11
|
+
import type { SignedSshBase } from './connect.js';
|
|
12
|
+
/**
|
|
13
|
+
* Ask the OS for a free TCP port by binding :0 then releasing it.
|
|
14
|
+
* Small TOCTOU window between release and ssh re-binding it — acceptable
|
|
15
|
+
* for a deploy tool (the race would only surface as an ssh bind error, which
|
|
16
|
+
* is reported and the host marked unreachable).
|
|
17
|
+
*/
|
|
18
|
+
export declare function pickFreePort(): Promise<number>;
|
|
19
|
+
/** A local-forward specification: bind 127.0.0.1:lport → rhost:rport over the ssh channel. */
|
|
20
|
+
export interface ForwardSpec {
|
|
21
|
+
bindHost: string;
|
|
22
|
+
localPort: number;
|
|
23
|
+
remoteHost: string;
|
|
24
|
+
remotePort: number;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Build the `ssh -N -L ...` argv from a signed base and a forward spec.
|
|
28
|
+
* Uses BatchMode + ConnectTimeout to match the codebase idiom (haproxy.ts).
|
|
29
|
+
*/
|
|
30
|
+
export declare function buildForwardArgs(base: SignedSshBase, spec: ForwardSpec, connectTimeoutSeconds: number): string[];
|
|
31
|
+
/** Options accepted by `znvault ssh forward`. Extends ConnectOptions with forward-specific fields. */
|
|
32
|
+
export interface ForwardOptions extends ConnectOptions {
|
|
33
|
+
/** -L spec: "[bindHost:]lport:rhost:rport". lport 0 = OS-assigned. */
|
|
34
|
+
L?: string;
|
|
35
|
+
/** Print one JSON line with the chosen local port and keep running. */
|
|
36
|
+
printPort?: boolean;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Parse a `-L` forward spec. Accepts 4-part (bindHost:lport:rhost:rport) or
|
|
40
|
+
* 3-part (lport:rhost:rport, bindHost defaults to 127.0.0.1).
|
|
41
|
+
*/
|
|
42
|
+
export declare function parseForwardOption(spec: string): ForwardSpec;
|
|
43
|
+
/**
|
|
44
|
+
* Run the forward: sign the cert, pick a port if lport==0, spawn `ssh -N -L`,
|
|
45
|
+
* and (in --print-port mode) emit one JSON line to stdout then hold the tunnel.
|
|
46
|
+
*/
|
|
47
|
+
export declare function runForward(destination: string, options: ForwardOptions): Promise<void>;
|
|
48
|
+
export declare function registerForwardCommand(parent: Command): void;
|
|
49
|
+
//# sourceMappingURL=forward.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"forward.d.ts","sourceRoot":"","sources":["../../../src/commands/ssh/forward.ts"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAIzC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAElD;;;;;GAKG;AACH,wBAAgB,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC,CAc9C;AAED,8FAA8F;AAC9F,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,aAAa,EACnB,IAAI,EAAE,WAAW,EACjB,qBAAqB,EAAE,MAAM,GAC5B,MAAM,EAAE,CAQV;AAED,sGAAsG;AACtG,MAAM,WAAW,cAAe,SAAQ,cAAc;IACpD,sEAAsE;IACtE,CAAC,CAAC,EAAE,MAAM,CAAC;IACX,uEAAuE;IACvE,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,CAmB5D;AAKD;;;GAGG;AACH,wBAAsB,UAAU,CAC9B,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,IAAI,CAAC,CAwEf;AAED,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI,CAiB5D"}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
// Path: src/commands/ssh/forward.ts
|
|
2
|
+
import * as net from 'node:net';
|
|
3
|
+
import * as output from '../../lib/output.js';
|
|
4
|
+
import { ensureSignedSshBase } from './connect.js';
|
|
5
|
+
/**
|
|
6
|
+
* Ask the OS for a free TCP port by binding :0 then releasing it.
|
|
7
|
+
* Small TOCTOU window between release and ssh re-binding it — acceptable
|
|
8
|
+
* for a deploy tool (the race would only surface as an ssh bind error, which
|
|
9
|
+
* is reported and the host marked unreachable).
|
|
10
|
+
*/
|
|
11
|
+
export function pickFreePort() {
|
|
12
|
+
return new Promise((resolve, reject) => {
|
|
13
|
+
const srv = net.createServer();
|
|
14
|
+
srv.once('error', reject);
|
|
15
|
+
srv.listen(0, '127.0.0.1', () => {
|
|
16
|
+
const addr = srv.address();
|
|
17
|
+
if (addr && typeof addr === 'object') {
|
|
18
|
+
const port = addr.port;
|
|
19
|
+
srv.close(() => { resolve(port); });
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
srv.close(() => { reject(new Error('Failed to obtain a free port')); });
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Build the `ssh -N -L ...` argv from a signed base and a forward spec.
|
|
29
|
+
* Uses BatchMode + ConnectTimeout to match the codebase idiom (haproxy.ts).
|
|
30
|
+
*/
|
|
31
|
+
export function buildForwardArgs(base, spec, connectTimeoutSeconds) {
|
|
32
|
+
const args = [...base.baseSshArgs];
|
|
33
|
+
args.push('-o', 'BatchMode=yes');
|
|
34
|
+
args.push('-o', `ConnectTimeout=${connectTimeoutSeconds}`);
|
|
35
|
+
args.push('-N');
|
|
36
|
+
args.push('-L', `${spec.bindHost}:${spec.localPort}:${spec.remoteHost}:${spec.remotePort}`);
|
|
37
|
+
args.push(base.user ? `${base.user}@${base.host}` : base.host);
|
|
38
|
+
return args;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Parse a `-L` forward spec. Accepts 4-part (bindHost:lport:rhost:rport) or
|
|
42
|
+
* 3-part (lport:rhost:rport, bindHost defaults to 127.0.0.1).
|
|
43
|
+
*/
|
|
44
|
+
export function parseForwardOption(spec) {
|
|
45
|
+
const parts = spec.split(':');
|
|
46
|
+
if (parts.length === 4) {
|
|
47
|
+
return {
|
|
48
|
+
bindHost: parts[0],
|
|
49
|
+
localPort: Number(parts[1]),
|
|
50
|
+
remoteHost: parts[2],
|
|
51
|
+
remotePort: Number(parts[3]),
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
if (parts.length === 3) {
|
|
55
|
+
return {
|
|
56
|
+
bindHost: '127.0.0.1',
|
|
57
|
+
localPort: Number(parts[0]),
|
|
58
|
+
remoteHost: parts[1],
|
|
59
|
+
remotePort: Number(parts[2]),
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
throw new Error(`Invalid forward spec "${spec}". Use "[bindHost:]localPort:remoteHost:remotePort".`);
|
|
63
|
+
}
|
|
64
|
+
const DEFAULT_FORWARD_REMOTE_PORT = 9100;
|
|
65
|
+
const FORWARD_CONNECT_TIMEOUT_SECONDS = 10;
|
|
66
|
+
/**
|
|
67
|
+
* Run the forward: sign the cert, pick a port if lport==0, spawn `ssh -N -L`,
|
|
68
|
+
* and (in --print-port mode) emit one JSON line to stdout then hold the tunnel.
|
|
69
|
+
*/
|
|
70
|
+
export async function runForward(destination, options) {
|
|
71
|
+
const { spawn } = await import('child_process');
|
|
72
|
+
const spec = options.L
|
|
73
|
+
? parseForwardOption(options.L)
|
|
74
|
+
: { bindHost: '127.0.0.1', localPort: 0, remoteHost: '127.0.0.1', remotePort: DEFAULT_FORWARD_REMOTE_PORT };
|
|
75
|
+
// Resolve a concrete local port (O1): pick a free one when 0 was requested.
|
|
76
|
+
if (spec.localPort === 0) {
|
|
77
|
+
spec.localPort = await pickFreePort();
|
|
78
|
+
}
|
|
79
|
+
let base;
|
|
80
|
+
try {
|
|
81
|
+
base = await ensureSignedSshBase(destination, options);
|
|
82
|
+
}
|
|
83
|
+
catch (err) {
|
|
84
|
+
output.error(err instanceof Error ? err.message : String(err));
|
|
85
|
+
process.exit(1);
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
const sshArgs = buildForwardArgs(base, spec, FORWARD_CONNECT_TIMEOUT_SECONDS);
|
|
89
|
+
if (options.dryRun) {
|
|
90
|
+
output.section('Dry Run');
|
|
91
|
+
output.keyValue({
|
|
92
|
+
'Key': base.keyPath,
|
|
93
|
+
'Certificate': base.certPath,
|
|
94
|
+
'Forward': `${spec.bindHost}:${spec.localPort} → ${base.host}:${spec.remotePort}`,
|
|
95
|
+
'User': base.user ?? '(default)',
|
|
96
|
+
});
|
|
97
|
+
console.log();
|
|
98
|
+
output.info(`Would execute: ssh ${sshArgs.join(' ')}`);
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
// All human/log output goes to STDERR so stdout stays a clean machine channel.
|
|
102
|
+
const sshProcess = spawn('ssh', sshArgs, {
|
|
103
|
+
stdio: ['ignore', 'ignore', 'inherit'],
|
|
104
|
+
env: process.env,
|
|
105
|
+
});
|
|
106
|
+
let exited = false;
|
|
107
|
+
sshProcess.on('error', (err) => {
|
|
108
|
+
exited = true;
|
|
109
|
+
process.stderr.write(`Failed to start SSH: ${err.message}\n`);
|
|
110
|
+
process.exit(1);
|
|
111
|
+
});
|
|
112
|
+
sshProcess.on('close', (code) => {
|
|
113
|
+
exited = true;
|
|
114
|
+
process.exit(code ?? 0);
|
|
115
|
+
});
|
|
116
|
+
// Teardown on our own termination so we never orphan the ssh -N child.
|
|
117
|
+
const cleanup = () => { if (!exited && sshProcess.pid)
|
|
118
|
+
sshProcess.kill('SIGTERM'); };
|
|
119
|
+
process.on('SIGINT', () => { cleanup(); process.exit(0); });
|
|
120
|
+
process.on('SIGTERM', () => { cleanup(); process.exit(0); });
|
|
121
|
+
if (options.printPort) {
|
|
122
|
+
// ssh -N has no "ready" signal on stdout; give it a moment to establish,
|
|
123
|
+
// then emit the contract line. forwardUp = ssh started + port bound by us.
|
|
124
|
+
await new Promise((r) => setTimeout(r, 300));
|
|
125
|
+
if (!exited) {
|
|
126
|
+
process.stdout.write(JSON.stringify({ localPort: spec.localPort, pid: sshProcess.pid, forwardUp: true }) + '\n');
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
process.stderr.write(`Forwarding 127.0.0.1:${spec.localPort} → ${base.host}:${spec.remotePort} (Ctrl-C to stop)\n`);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
export function registerForwardCommand(parent) {
|
|
134
|
+
parent
|
|
135
|
+
.command('forward <destination>')
|
|
136
|
+
.description('Open an SSH local port-forward authenticated by the vault SSH CA')
|
|
137
|
+
.option('-L <spec>', 'Forward spec: [bindHost:]localPort:remoteHost:remotePort (localPort 0 = auto)')
|
|
138
|
+
.option('--print-port', 'Print {"localPort","pid","forwardUp"} JSON then hold the tunnel (machine mode)')
|
|
139
|
+
.option('-i, --identity <file>', 'Path to SSH private key')
|
|
140
|
+
.option('-p, --port <port>', 'SSH port', '22')
|
|
141
|
+
.option('--principals <principals>', 'Principals for signing (comma-separated)')
|
|
142
|
+
.option('--ttl <ttl>', 'Certificate TTL (e.g., 8h, 1d)')
|
|
143
|
+
.option('--tenant <id>', 'Tenant ID (superadmin only)')
|
|
144
|
+
.option('--force-sign', 'Force re-signing even if certificate is valid')
|
|
145
|
+
.option('--dry-run', 'Show what would be done without executing SSH')
|
|
146
|
+
.option('-v, --verbose', 'Show verbose output')
|
|
147
|
+
.action(async (destination, options) => {
|
|
148
|
+
await runForward(destination, options);
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
//# sourceMappingURL=forward.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"forward.js","sourceRoot":"","sources":["../../../src/commands/ssh/forward.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/ssh/index.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/ssh/index.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAazC,OAAO,EAGL,KAAK,eAAe,EACrB,MAAM,8BAA8B,CAAC;AAkDtC,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,eAAe,GAAG,IAAI,CA8DjF;AAGD,cAAc,YAAY,CAAC;AAG3B,OAAO,EACL,iBAAiB,EACjB,kBAAkB,EAClB,kBAAkB,EAClB,eAAe,EACf,SAAS,EACT,QAAQ,EACR,SAAS,EACT,gBAAgB,EAChB,oBAAoB,EACpB,mBAAmB,GACpB,MAAM,cAAc,CAAC;AAGtB,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC"}
|
|
@@ -5,6 +5,7 @@ import { registerMappingCommands } from './mapping.js';
|
|
|
5
5
|
import { registerServerGroupCommands } from './server-group.js';
|
|
6
6
|
import { registerConfigCommands } from './config.js';
|
|
7
7
|
import { registerConnectCommand, executeConnect } from './connect.js';
|
|
8
|
+
import { registerForwardCommand } from './forward.js';
|
|
8
9
|
import { registerBookmarkCommands, resolveBookmark } from './bookmark.js';
|
|
9
10
|
import { registerSCPCommand } from './scp.js';
|
|
10
11
|
import { registerHostsCommand } from './hosts.js';
|
|
@@ -13,7 +14,7 @@ import { resolveContext, withRegisterContext, } from '../../lib/command-context.
|
|
|
13
14
|
// Known subcommands that should NOT be treated as destinations
|
|
14
15
|
const SSH_SUBCOMMANDS = new Set([
|
|
15
16
|
'ca', 'cert', 'mapping', 'server-group', 'config',
|
|
16
|
-
'bookmark', 'bm', 'hosts', 'scp', 'connect', 'exec',
|
|
17
|
+
'bookmark', 'bm', 'hosts', 'scp', 'connect', 'exec', 'forward',
|
|
17
18
|
'help', '--help', '-h',
|
|
18
19
|
]);
|
|
19
20
|
/**
|
|
@@ -55,6 +56,12 @@ export function registerSSHCommands(parent, opts) {
|
|
|
55
56
|
const ssh = parent
|
|
56
57
|
.command('ssh')
|
|
57
58
|
.description('SSH CA management and quick connect (znvault ssh user@host)')
|
|
59
|
+
// Parse options relative to position: options that appear AFTER a subcommand
|
|
60
|
+
// name (e.g. `ssh connect --dry-run ...`) are handed to the subcommand rather
|
|
61
|
+
// than being swallowed by this parent (which also declares --dry-run/--ttl/-i
|
|
62
|
+
// for the `ssh user@host` shortcut). Without this, Commander attributes those
|
|
63
|
+
// options to the parent and the subcommand's action sees them as undefined.
|
|
64
|
+
.enablePositionalOptions()
|
|
58
65
|
.argument('[destination]', 'Host to connect to (user@host or bookmark name)')
|
|
59
66
|
.argument('[command...]', 'Remote command to execute')
|
|
60
67
|
.option('-i, --identity <file>', 'Path to SSH private key')
|
|
@@ -102,6 +109,7 @@ export function registerSSHCommands(parent, opts) {
|
|
|
102
109
|
registerHostsCommand(ssh);
|
|
103
110
|
registerSCPCommand(ssh);
|
|
104
111
|
registerConnectCommand(ssh);
|
|
112
|
+
registerForwardCommand(ssh);
|
|
105
113
|
registerExecCommand(ssh);
|
|
106
114
|
});
|
|
107
115
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/commands/ssh/index.ts"],"names":[],"mappings":"AAAA,kCAAkC;AAsBlC,OAAO,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAC7C,OAAO,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;AACjD,OAAO,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAC;AACvD,OAAO,EAAE,2BAA2B,EAAE,MAAM,mBAAmB,CAAC;AAChE,OAAO,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,EAAE,sBAAsB,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACtE,OAAO,EAAE,wBAAwB,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAC1E,OAAO,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAC9C,OAAO,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAClD,OAAO,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAEhD,OAAO,EACL,cAAc,EACd,mBAAmB,GAEpB,MAAM,8BAA8B,CAAC;AAEtC,+DAA+D;AAC/D,MAAM,eAAe,GAAG,IAAI,GAAG,CAAC;IAC9B,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,cAAc,EAAE,QAAQ;IACjD,UAAU,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/commands/ssh/index.ts"],"names":[],"mappings":"AAAA,kCAAkC;AAsBlC,OAAO,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAC7C,OAAO,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;AACjD,OAAO,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAC;AACvD,OAAO,EAAE,2BAA2B,EAAE,MAAM,mBAAmB,CAAC;AAChE,OAAO,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,EAAE,sBAAsB,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACtE,OAAO,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAC;AACtD,OAAO,EAAE,wBAAwB,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAC1E,OAAO,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAC9C,OAAO,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAClD,OAAO,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAEhD,OAAO,EACL,cAAc,EACd,mBAAmB,GAEpB,MAAM,8BAA8B,CAAC;AAEtC,+DAA+D;AAC/D,MAAM,eAAe,GAAG,IAAI,GAAG,CAAC;IAC9B,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,cAAc,EAAE,QAAQ;IACjD,UAAU,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS;IAC9D,MAAM,EAAE,QAAQ,EAAE,IAAI;CACvB,CAAC,CAAC;AAEH;;GAEG;AACH,SAAS,oBAAoB,CAAC,GAAW;IACvC,kDAAkD;IAClD,IAAI,eAAe,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;QAC7B,OAAO,KAAK,CAAC;IACf,CAAC;IAED,qCAAqC;IACrC,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QACtB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,gBAAgB;IAChB,IAAI,eAAe,CAAC,GAAG,CAAC,EAAE,CAAC;QACzB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,sCAAsC;IACtC,IAAI,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACjD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,oCAAoC;IACpC,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QACtB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,kEAAkE;IAClE,2DAA2D;IAC3D,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,qBAAqB,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;QAC5D,sDAAsD;QACtD,0EAA0E;QAC1E,0DAA0D;QAC1D,OAAO,KAAK,CAAC;IACf,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,MAAe,EAAE,IAAsB;IACzE,MAAM,GAAG,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC;IACjC,MAAM,GAAG,GAAG,MAAM;SACf,OAAO,CAAC,KAAK,CAAC;SACd,WAAW,CAAC,6DAA6D,CAAC;QAC3E,6EAA6E;QAC7E,8EAA8E;QAC9E,8EAA8E;QAC9E,8EAA8E;QAC9E,4EAA4E;SAC3E,uBAAuB,EAAE;SACzB,QAAQ,CAAC,eAAe,EAAE,iDAAiD,CAAC;SAC5E,QAAQ,CAAC,cAAc,EAAE,2BAA2B,CAAC;SACrD,MAAM,CAAC,uBAAuB,EAAE,yBAAyB,CAAC;SAC1D,MAAM,CAAC,mBAAmB,EAAE,UAAU,EAAE,IAAI,CAAC;SAC7C,MAAM,CAAC,2BAA2B,EAAE,0CAA0C,CAAC;SAC/E,MAAM,CAAC,aAAa,EAAE,gCAAgC,CAAC;SACvD,MAAM,CAAC,eAAe,EAAE,6BAA6B,CAAC;SACtD,MAAM,CAAC,cAAc,EAAE,+CAA+C,CAAC;SACvE,MAAM,CAAC,WAAW,EAAE,+CAA+C,CAAC;SACpE,MAAM,CAAC,eAAe,EAAE,qBAAqB,CAAC;SAC9C,MAAM,CAAC,IAAI,EAAE,kCAAkC,CAAC;SAChD,MAAM,CAAC,IAAI,EAAE,oCAAoC,CAAC;SAClD,kBAAkB,CAAC,KAAK,CAAC;SACzB,MAAM,CAAC,KAAK,EAAE,WAA+B,EAAE,aAAuB,EAAE,OAAuB,EAAE,EAAE;QAClG,wCAAwC;QACxC,IAAI,CAAC,WAAW,EAAE,CAAC;YACjB,GAAG,CAAC,UAAU,EAAE,CAAC;YACjB,OAAO;QACT,CAAC;QAED,uCAAuC;QACvC,IAAI,oBAAoB,CAAC,WAAW,CAAC,EAAE,CAAC;YACtC,MAAM,cAAc,CAAC,WAAW,EAAE,aAAa,EAAE,OAAO,CAAC,CAAC;QAC5D,CAAC;aAAM,CAAC;YACN,4DAA4D;YAC5D,wBAAwB;YACxB,OAAO,CAAC,KAAK,CAAC,sCAAsC,WAAW,EAAE,CAAC,CAAC;YACnE,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;YAClB,OAAO,CAAC,KAAK,CAAC,+CAA+C,CAAC,CAAC;YAC/D,OAAO,CAAC,KAAK,CAAC,qDAAqD,CAAC,CAAC;YACrE,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;YAClB,GAAG,CAAC,UAAU,EAAE,CAAC;YACjB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC,CAAC,CAAC;IAEL,6EAA6E;IAC7E,iFAAiF;IACjF,mBAAmB,CAAC,GAAG,EAAE,GAAG,EAAE;QAC5B,kBAAkB,CAAC,GAAG,CAAC,CAAC;QACxB,oBAAoB,CAAC,GAAG,CAAC,CAAC;QAC1B,uBAAuB,CAAC,GAAG,CAAC,CAAC;QAC7B,2BAA2B,CAAC,GAAG,CAAC,CAAC;QACjC,sBAAsB,CAAC,GAAG,CAAC,CAAC;QAC5B,wBAAwB,CAAC,GAAG,CAAC,CAAC;QAC9B,oBAAoB,CAAC,GAAG,CAAC,CAAC;QAC1B,kBAAkB,CAAC,GAAG,CAAC,CAAC;QACxB,sBAAsB,CAAC,GAAG,CAAC,CAAC;QAC5B,sBAAsB,CAAC,GAAG,CAAC,CAAC;QAC5B,mBAAmB,CAAC,GAAG,CAAC,CAAC;IAC3B,CAAC,CAAC,CAAC;AACL,CAAC;AAED,mCAAmC;AACnC,cAAc,YAAY,CAAC;AAE3B,wCAAwC;AACxC,OAAO,EACL,iBAAiB,EACjB,kBAAkB,EAClB,kBAAkB,EAClB,eAAe,EACf,SAAS,EACT,QAAQ,EACR,SAAS,EACT,gBAAgB,EAChB,oBAAoB,EACpB,mBAAmB,GACpB,MAAM,cAAc,CAAC;AAEtB,8BAA8B;AAC9B,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -49,6 +49,12 @@ const program = new Command();
|
|
|
49
49
|
program
|
|
50
50
|
.name('znvault')
|
|
51
51
|
.description('ZnVault Administration CLI')
|
|
52
|
+
// Enable positional options on the root program so that options appearing after
|
|
53
|
+
// a subcommand name are parsed relative to position. Commander requires this on
|
|
54
|
+
// ancestor commands for nested positional parsing to reach grandchild commands
|
|
55
|
+
// (e.g. `znvault ssh connect --dry-run`), where the `ssh` parent also declares
|
|
56
|
+
// its own options for the `ssh user@host` shortcut. See src/commands/ssh/index.ts.
|
|
57
|
+
.enablePositionalOptions()
|
|
52
58
|
.version(getVersion())
|
|
53
59
|
.option('--url <url>', 'Vault server URL')
|
|
54
60
|
.option('--insecure', 'Skip TLS certificate verification')
|
|
@@ -80,6 +86,13 @@ program
|
|
|
80
86
|
if (parentName === 'completion' || cmdPath === 'completion') {
|
|
81
87
|
return;
|
|
82
88
|
}
|
|
89
|
+
// Skip profile indicator for `ssh forward --print-port` — its stdout is a
|
|
90
|
+
// machine channel (JSON contract line) consumed by the deploy tunnel manager.
|
|
91
|
+
if (cmdPath === 'forward' &&
|
|
92
|
+
parentName === 'ssh' &&
|
|
93
|
+
actionCommand.opts().printPort === true) {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
83
96
|
// Show current profile indicator
|
|
84
97
|
const config = getConfig();
|
|
85
98
|
profileIndicator(getActiveProfileName(), config.url);
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AACnE,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAE1D,iFAAiF;AACjF,qDAAqD;AACrD,uBAAuB,CAAC,OAAO,CAAC,SAAqE,CAAC,CAAC;AACvG,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,0BAA0B,EAAE,MAAM,gCAAgC,CAAC;AAC5E,OAAO,EAAE,0BAA0B,EAAE,MAAM,0BAA0B,CAAC;AACtE,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,yBAAyB,EAAE,MAAM,yBAAyB,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,2BAA2B,EAAE,MAAM,2BAA2B,CAAC;AACxE,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,4BAA4B,EAAE,MAAM,4BAA4B,CAAC;AAC1E,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,0BAA0B,EAAE,MAAM,2BAA2B,CAAC;AACvE,OAAO,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,0BAA0B,EAAE,MAAM,0BAA0B,CAAC;AACtE,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AACpE,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,8BAA8B,EAAE,MAAM,+BAA+B,CAAC;AAC/E,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACzC,OAAO,EACL,iBAAiB,EACjB,oBAAoB,EACpB,SAAS,EACT,UAAU,EACV,cAAc,EACd,SAAS,EACT,mBAAmB,GACpB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,gBAAgB,EAAE,aAAa,EAAsB,MAAM,iBAAiB,CAAC;AAC3G,OAAO,EAAE,wBAAwB,EAAE,MAAM,qBAAqB,CAAC;AAC/D,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACnE,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAU5D,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,SAAS,CAAC;KACf,WAAW,CAAC,4BAA4B,CAAC;IAC1C,gFAAgF;IAChF,gFAAgF;IAChF,+EAA+E;IAC/E,+EAA+E;IAC/E,mFAAmF;KAClF,uBAAuB,EAAE;KACzB,OAAO,CAAC,UAAU,EAAE,CAAC;KACrB,MAAM,CAAC,aAAa,EAAE,kBAAkB,CAAC;KACzC,MAAM,CAAC,YAAY,EAAE,mCAAmC,CAAC;KACzD,MAAM,CAAC,kBAAkB,EAAE,sCAAsC,CAAC;KAClE,MAAM,CAAC,SAAS,EAAE,0CAA0C,CAAC;KAC7D,MAAM,CAAC,aAAa,EAAE,kEAAkE,CAAC;KACzF,IAAI,CAAC,WAAW,EAAE,CAAC,WAAW,EAAE,aAAa,EAAE,EAAE;IAChD,uBAAuB;IACvB,MAAM,IAAI,GAAG,WAAW,CAAC,IAAI,EAAiB,CAAC;IAE/C,4CAA4C;IAC5C,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;QACf,aAAa,CAAC,OAAO,CAAC,CAAC;IACzB,CAAC;IAED,+DAA+D;IAC/D,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;QACf,YAAY,CAAC,IAAI,CAAC,CAAC;IACrB,CAAC;IAED,kDAAkD;IAClD,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;QACjB,iBAAiB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAClC,CAAC;IAED,+BAA+B;IAC/B,IAAI,IAAI,CAAC,GAAG,KAAK,SAAS,IAAI,IAAI,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC1D,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC5C,CAAC;IAED,gFAAgF;IAChF,MAAM,OAAO,GAAG,aAAa,CAAC,IAAI,EAAE,CAAC;IACrC,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC;IAChD,IAAI,UAAU,KAAK,YAAY,IAAI,OAAO,KAAK,YAAY,EAAE,CAAC;QAC5D,OAAO;IACT,CAAC;IAED,0EAA0E;IAC1E,8EAA8E;IAC9E,IACE,OAAO,KAAK,SAAS;QACrB,UAAU,KAAK,KAAK;QACpB,aAAa,CAAC,IAAI,EAAE,CAAC,SAAS,KAAK,IAAI,EACvC,CAAC;QACD,OAAO;IACT,CAAC;IAED,iCAAiC;IACjC,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAC3B,gBAAgB,CAAC,oBAAoB,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC;AACvD,CAAC,CAAC,CAAC;AAEL,qEAAqE;AACrE,EAAE;AACF,8EAA8E;AAC9E,iDAAiD;AACjD,+DAA+D;AAC/D,kEAAkE;AAClE,EAAE;AACF,8EAA8E;AAC9E,4EAA4E;AAC5E,mEAAmE;AACnE,+CAA+C;AAC/C,oBAAoB,CAAC,OAAO,CAAC,CAAC;AAC9B,sBAAsB,CAAC,OAAO,CAAC,CAAC;AAChC,oBAAoB,CAAC,OAAO,CAAC,CAAC;AAC9B,0BAA0B,CAAC,OAAO,CAAC,CAAC;AACpC,qBAAqB,CAAC,OAAO,CAAC,CAAC;AAC/B,yBAAyB,CAAC,OAAO,CAAC,CAAC;AACnC,oBAAoB,CAAC,OAAO,CAAC,CAAC;AAC9B,qBAAqB,CAAC,OAAO,CAAC,CAAC;AAC/B,oBAAoB,CAAC,OAAO,CAAC,CAAC;AAC9B,sBAAsB,CAAC,OAAO,CAAC,CAAC;AAChC,sBAAsB,CAAC,OAAO,CAAC,CAAC;AAChC,sBAAsB,CAAC,OAAO,CAAC,CAAC;AAChC,2BAA2B,CAAC,OAAO,CAAC,CAAC;AACrC,sBAAsB,CAAC,OAAO,CAAC,CAAC;AAChC,mBAAmB,CAAC,OAAO,CAAC,CAAC;AAC7B,oBAAoB,CAAC,OAAO,CAAC,CAAC;AAC9B,4BAA4B,CAAC,OAAO,CAAC,CAAC;AACtC,mBAAmB,CAAC,OAAO,CAAC,CAAC;AAC7B,0BAA0B,CAAC,OAAO,CAAC,CAAC;AACpC,uBAAuB,CAAC,OAAO,CAAC,CAAC;AACjC,0BAA0B,CAAC,OAAO,CAAC,CAAC;AACpC,sBAAsB,CAAC,OAAO,CAAC,CAAC;AAChC,sBAAsB,CAAC,OAAO,CAAC,CAAC;AAChC,sBAAsB,CAAC,OAAO,CAAC,CAAC;AAChC,sBAAsB,CAAC,OAAO,CAAC,CAAC;AAChC,mBAAmB,CAAC,OAAO,CAAC,CAAC;AAC7B,qBAAqB,CAAC,OAAO,CAAC,CAAC;AAC/B,8BAA8B,CAAC,OAAO,CAAC,CAAC;AACxC,mBAAmB,CAAC,OAAO,CAAC,CAAC;AAC7B,qBAAqB,CAAC,OAAO,CAAC,CAAC;AAC/B,oBAAoB,CAAC,OAAO,CAAC,CAAC;AAE9B,6EAA6E;AAC7E,0BAA0B,CAAC,OAAO,CAAC,CAAC;AAEpC,kFAAkF;AAClF,oBAAoB,CAAC,OAAO,CAAC,CAAC;AAE9B,6CAA6C;AAC7C,wBAAwB,EAAE,CAAC;AAE3B;;GAEG;AACH,SAAS,YAAY;IACnB,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAC3B,MAAM,OAAO,GAAG,oBAAoB,EAAE,CAAC;IACvC,MAAM,WAAW,GAAG,cAAc,EAAE,CAAC;IACrC,MAAM,UAAU,GAAG,mBAAmB,EAAE,CAAC;IAEzC,IAAI,UAAU,GAA8B,MAAM,CAAC;IACnD,IAAI,QAA4B,CAAC;IACjC,IAAI,UAA8B,CAAC;IACnC,IAAI,YAAgC,CAAC;IAErC,IAAI,SAAS,EAAE,EAAE,CAAC;QAChB,UAAU,GAAG,QAAQ,CAAC;QACtB,IAAI,UAAU,EAAE,CAAC;YACf,UAAU,GAAG,UAAU,CAAC,IAAI,CAAC;YAC7B,YAAY,GAAG,UAAU,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,KAAK,CAAC;QACzD,CAAC;IACH,CAAC;SAAM,IAAI,WAAW,EAAE,WAAW,EAAE,CAAC;QACpC,UAAU,GAAG,KAAK,CAAC;QACnB,2CAA2C;QAC3C,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,WAAW,CAAC,WAAW,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;YACtD,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,QAAQ,EAAE,CAAwC,CAAC;YAC7G,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC,GAAG,CAAC;QAC7C,CAAC;QAAC,MAAM,CAAC;YACP,QAAQ,GAAG,eAAe,CAAC;QAC7B,CAAC;IACH,CAAC;IAED,OAAO;QACL,OAAO,EAAE,UAAU,EAAE;QACrB,OAAO;QACP,QAAQ,EAAE,MAAM,CAAC,GAAG;QACpB,UAAU;QACV,QAAQ;QACR,UAAU;QACV,YAAY;KACb,CAAC;AACJ,CAAC;AAED,yBAAyB;AACzB,KAAK,UAAU,IAAI;IACjB,mDAAmD;IACnD,IAAI,OAAO,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC9B,MAAM,MAAM,GAAG,YAAY,EAAE,CAAC;QAC9B,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;QACvC,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC,CAAC;QACtC,OAAO,CAAC,GAAG,CAAC,aAAa,EAAE,CAAC,CAAC;QAC7B,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC;QACxB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,6DAA6D;IAC7D,IAAI,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACpE,YAAY,CAAC,IAAI,CAAC,CAAC;IACrB,CAAC;IAED,mBAAmB;IACnB,MAAM,aAAa,GAAG,UAAU,EAAE,CAAC;IACnC,IAAI,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC7B,IAAI,CAAC;YACH,MAAM,YAAY,GAAG,MAAM,qBAAqB,CAC9C,aAAa,EACb,MAAM,EACN,SAAS,EACT,oBAAoB,CACrB,CAAC;YACF,YAAY,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC;QACzC,CAAC;QAAC,MAAM,CAAC;YACP,iEAAiE;QACnE,CAAC;IACH,CAAC;IAED,oBAAoB;IACpB,OAAO,CAAC,KAAK,EAAE,CAAC;AAClB,CAAC;AAED,WAAW;AACX,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACnB,OAAO,CAAC,KAAK,CAAC,YAAY,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;IAC9E,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|