@p0security/cli 0.6.1 → 0.7.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/__tests__/ssh.test.js +18 -4
- package/dist/commands/allow.d.ts +10 -0
- package/dist/commands/allow.js +57 -0
- package/dist/commands/index.js +2 -0
- package/dist/commands/scp.js +3 -13
- package/dist/commands/shared.d.ts +6 -0
- package/dist/commands/shared.js +12 -1
- package/dist/commands/ssh.js +15 -14
- package/dist/index.d.ts +1 -0
- package/dist/index.js +12 -1
- package/dist/plugins/aws/ssm/index.d.ts +1 -3
- package/dist/plugins/aws/ssm/index.js +83 -240
- package/dist/plugins/login.js +2 -0
- package/dist/plugins/oidc/login.d.ts +5 -0
- package/dist/plugins/oidc/login.js +133 -0
- package/dist/plugins/okta/login.js +4 -88
- package/dist/plugins/ping/login.d.ts +13 -0
- package/dist/plugins/ping/login.js +16 -0
- package/dist/plugins/ssh-agent/index.d.ts +10 -0
- package/dist/plugins/ssh-agent/index.js +142 -0
- package/dist/plugins/ssh-agent/types.d.ts +17 -0
- package/dist/plugins/ssh-agent/types.js +2 -0
- package/dist/types/allow.d.ts +14 -0
- package/dist/types/allow.js +2 -0
- package/dist/types/org.d.ts +12 -4
- package/dist/types/org.js +10 -0
- package/dist/util.d.ts +3 -0
- package/dist/util.js +11 -1
- package/package.json +1 -3
|
@@ -36,7 +36,7 @@ jest.mock("../../drivers/auth");
|
|
|
36
36
|
jest.mock("../../drivers/stdio");
|
|
37
37
|
jest.mock("../../plugins/aws/ssm");
|
|
38
38
|
const mockFetchCommand = api_1.fetchCommand;
|
|
39
|
-
const
|
|
39
|
+
const mockSshOrScp = ssm_1.sshOrScp;
|
|
40
40
|
const mockPrint1 = stdio_1.print1;
|
|
41
41
|
const mockPrint2 = stdio_1.print2;
|
|
42
42
|
(0, firestore_1.mockGetDoc)({
|
|
@@ -46,7 +46,6 @@ const mockPrint2 = stdio_1.print2;
|
|
|
46
46
|
},
|
|
47
47
|
},
|
|
48
48
|
});
|
|
49
|
-
mockSsm.mockResolvedValue({});
|
|
50
49
|
describe("ssh", () => {
|
|
51
50
|
describe.each([
|
|
52
51
|
["persistent", true],
|
|
@@ -97,7 +96,22 @@ describe("ssh", () => {
|
|
|
97
96
|
yield Promise.race([wait, promise]);
|
|
98
97
|
yield expect(wait).resolves.toBeUndefined();
|
|
99
98
|
}));
|
|
100
|
-
it("should call
|
|
99
|
+
it("should call sshOrScp with non-interactive command", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
100
|
+
const promise = (0, ssh_1.sshCommand)((0, yargs_1.default)()).parse(`ssh some-instance do something`);
|
|
101
|
+
yield (0, util_1.sleep)(100); // Need to wait for listen before trigger in tests
|
|
102
|
+
firestore_2.onSnapshot.trigger({
|
|
103
|
+
status: "APPROVED",
|
|
104
|
+
});
|
|
105
|
+
yield (0, util_1.sleep)(100); // Need to wait for listen before trigger in tests
|
|
106
|
+
firestore_2.onSnapshot.trigger({
|
|
107
|
+
status: "DONE",
|
|
108
|
+
});
|
|
109
|
+
yield expect(promise).resolves.toBeDefined();
|
|
110
|
+
expect(mockPrint2.mock.calls).toMatchSnapshot("stderr");
|
|
111
|
+
expect(mockPrint1).not.toHaveBeenCalled();
|
|
112
|
+
expect(mockSshOrScp).toHaveBeenCalled();
|
|
113
|
+
}));
|
|
114
|
+
it("should call sshOrScp with interactive session", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
101
115
|
const promise = (0, ssh_1.sshCommand)((0, yargs_1.default)()).parse(`ssh some-instance`);
|
|
102
116
|
yield (0, util_1.sleep)(100); // Need to wait for listen before trigger in tests
|
|
103
117
|
firestore_2.onSnapshot.trigger({
|
|
@@ -110,7 +124,7 @@ describe("ssh", () => {
|
|
|
110
124
|
yield expect(promise).resolves.toBeDefined();
|
|
111
125
|
expect(mockPrint2.mock.calls).toMatchSnapshot("stderr");
|
|
112
126
|
expect(mockPrint1).not.toHaveBeenCalled();
|
|
113
|
-
expect(
|
|
127
|
+
expect(mockSshOrScp).toHaveBeenCalled();
|
|
114
128
|
}));
|
|
115
129
|
});
|
|
116
130
|
});
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { AllowResponse } from "../types/allow";
|
|
2
|
+
import { Authn } from "../types/identity";
|
|
3
|
+
import yargs from "yargs";
|
|
4
|
+
export declare const allowCommand: (yargs: yargs.Argv<{}>) => yargs.Argv<{
|
|
5
|
+
arguments: string[];
|
|
6
|
+
}>;
|
|
7
|
+
export declare const allow: (args: yargs.ArgumentsCamelCase<{
|
|
8
|
+
arguments: string[];
|
|
9
|
+
wait?: boolean;
|
|
10
|
+
}>, authn?: Authn) => Promise<AllowResponse | undefined>;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.allow = exports.allowCommand = void 0;
|
|
13
|
+
/** Copyright © 2024-present P0 Security
|
|
14
|
+
|
|
15
|
+
This file is part of @p0security/cli
|
|
16
|
+
|
|
17
|
+
@p0security/cli is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 3 of the License.
|
|
18
|
+
|
|
19
|
+
@p0security/cli is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
20
|
+
|
|
21
|
+
You should have received a copy of the GNU General Public License along with @p0security/cli. If not, see <https://www.gnu.org/licenses/>.
|
|
22
|
+
**/
|
|
23
|
+
const api_1 = require("../drivers/api");
|
|
24
|
+
const auth_1 = require("../drivers/auth");
|
|
25
|
+
const firestore_1 = require("../drivers/firestore");
|
|
26
|
+
const stdio_1 = require("../drivers/stdio");
|
|
27
|
+
const allowArgs = (yargs) => yargs
|
|
28
|
+
.parserConfiguration({ "unknown-options-as-args": true })
|
|
29
|
+
.help(false) // Turn off help in order to forward the --help command to the backend so P0 can provide the available requestable resources
|
|
30
|
+
.option("wait", {
|
|
31
|
+
alias: "w",
|
|
32
|
+
boolean: true,
|
|
33
|
+
default: false,
|
|
34
|
+
describe: "Block until the command is completed",
|
|
35
|
+
})
|
|
36
|
+
.option("arguments", {
|
|
37
|
+
array: true,
|
|
38
|
+
string: true,
|
|
39
|
+
default: [],
|
|
40
|
+
});
|
|
41
|
+
const allowCommand = (yargs) => yargs.command("allow [arguments..]", "Create standing access for a resource", allowArgs, (0, firestore_1.guard)(exports.allow));
|
|
42
|
+
exports.allowCommand = allowCommand;
|
|
43
|
+
const allow = (args, authn) => __awaiter(void 0, void 0, void 0, function* () {
|
|
44
|
+
const resolvedAuthn = authn !== null && authn !== void 0 ? authn : (yield (0, auth_1.authenticate)());
|
|
45
|
+
const data = yield (0, api_1.fetchCommand)(resolvedAuthn, args, [
|
|
46
|
+
"allow",
|
|
47
|
+
...args.arguments,
|
|
48
|
+
]);
|
|
49
|
+
if (data && "ok" in data && "message" in data && data.ok) {
|
|
50
|
+
(0, stdio_1.print2)(data.message);
|
|
51
|
+
return data;
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
throw data;
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
exports.allow = allow;
|
package/dist/commands/index.js
CHANGED
|
@@ -16,6 +16,7 @@ You should have received a copy of the GNU General Public License along with @p0
|
|
|
16
16
|
**/
|
|
17
17
|
const stdio_1 = require("../drivers/stdio");
|
|
18
18
|
const version_1 = require("../middlewares/version");
|
|
19
|
+
const allow_1 = require("./allow");
|
|
19
20
|
const aws_1 = require("./aws");
|
|
20
21
|
const login_1 = require("./login");
|
|
21
22
|
const ls_1 = require("./ls");
|
|
@@ -30,6 +31,7 @@ const commands = [
|
|
|
30
31
|
login_1.loginCommand,
|
|
31
32
|
ls_1.lsCommand,
|
|
32
33
|
request_1.requestCommand,
|
|
34
|
+
allow_1.allowCommand,
|
|
33
35
|
ssh_1.sshCommand,
|
|
34
36
|
scp_1.scpCommand,
|
|
35
37
|
];
|
package/dist/commands/scp.js
CHANGED
|
@@ -8,9 +8,6 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
8
8
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
9
|
});
|
|
10
10
|
};
|
|
11
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
-
};
|
|
14
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
12
|
exports.scpCommand = void 0;
|
|
16
13
|
/** Copyright © 2024-present P0 Security
|
|
@@ -28,7 +25,6 @@ const auth_1 = require("../drivers/auth");
|
|
|
28
25
|
const firestore_1 = require("../drivers/firestore");
|
|
29
26
|
const ssm_1 = require("../plugins/aws/ssm");
|
|
30
27
|
const shared_1 = require("./shared");
|
|
31
|
-
const node_forge_1 = __importDefault(require("node-forge"));
|
|
32
28
|
const scpCommand = (yargs) => yargs.command("scp <source> <destination>",
|
|
33
29
|
// TODO (ENG-1930): support scp across multiple remote hosts.
|
|
34
30
|
"SCP copies files between a local and remote host.", (yargs) => yargs
|
|
@@ -61,7 +57,7 @@ const scpCommand = (yargs) => yargs.command("scp <source> <destination>",
|
|
|
61
57
|
})
|
|
62
58
|
.option("debug", {
|
|
63
59
|
type: "boolean",
|
|
64
|
-
describe: "Print debug information
|
|
60
|
+
describe: "Print debug information. The ssh-agent subprocess is not terminated automatically.",
|
|
65
61
|
}), (0, firestore_1.guard)(scpAction));
|
|
66
62
|
exports.scpCommand = scpCommand;
|
|
67
63
|
/** Transfers files between a local and remote hosts using SSH.
|
|
@@ -78,7 +74,7 @@ const scpAction = (args) => __awaiter(void 0, void 0, void 0, function* () {
|
|
|
78
74
|
if (!requestId) {
|
|
79
75
|
throw "Server did not return a request id. Please contact support@p0.dev for assistance.";
|
|
80
76
|
}
|
|
81
|
-
const { publicKey, privateKey } = createKeyPair();
|
|
77
|
+
const { publicKey, privateKey } = (0, shared_1.createKeyPair)();
|
|
82
78
|
const result = yield (0, api_1.fetchExerciseGrant)(authn, {
|
|
83
79
|
requestId,
|
|
84
80
|
destination: host,
|
|
@@ -86,7 +82,7 @@ const scpAction = (args) => __awaiter(void 0, void 0, void 0, function* () {
|
|
|
86
82
|
});
|
|
87
83
|
// replace the host with the linuxUserName@instanceId
|
|
88
84
|
const { source, destination } = replaceHostWithInstance(result, args);
|
|
89
|
-
yield (0, ssm_1.
|
|
85
|
+
yield (0, ssm_1.sshOrScp)(authn, result, Object.assign(Object.assign({}, args), { source,
|
|
90
86
|
destination }), privateKey);
|
|
91
87
|
});
|
|
92
88
|
/** If a path is not explicitly local, use this pattern to determine if it's remote */
|
|
@@ -117,9 +113,3 @@ const replaceHostWithInstance = (result, args) => {
|
|
|
117
113
|
}
|
|
118
114
|
return { source, destination };
|
|
119
115
|
};
|
|
120
|
-
const createKeyPair = () => {
|
|
121
|
-
const rsaKeyPair = node_forge_1.default.pki.rsa.generateKeyPair({ bits: 2048 });
|
|
122
|
-
const privateKey = node_forge_1.default.pki.privateKeyToPem(rsaKeyPair.privateKey);
|
|
123
|
-
const publicKey = node_forge_1.default.ssh.publicKeyToOpenSSH(rsaKeyPair.publicKey);
|
|
124
|
-
return { publicKey, privateKey };
|
|
125
|
-
};
|
|
@@ -29,7 +29,13 @@ export declare type SshCommandArgs = BaseSshCommandArgs & {
|
|
|
29
29
|
destination: string;
|
|
30
30
|
L?: string;
|
|
31
31
|
N?: boolean;
|
|
32
|
+
A?: boolean;
|
|
32
33
|
arguments: string[];
|
|
33
34
|
command?: string;
|
|
35
|
+
debug?: boolean;
|
|
34
36
|
};
|
|
35
37
|
export declare const provisionRequest: (authn: Authn, args: yargs.ArgumentsCamelCase<BaseSshCommandArgs>, destination: string) => Promise<string | undefined>;
|
|
38
|
+
export declare const createKeyPair: () => {
|
|
39
|
+
publicKey: string;
|
|
40
|
+
privateKey: string;
|
|
41
|
+
};
|
package/dist/commands/shared.js
CHANGED
|
@@ -8,8 +8,11 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
8
8
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
9
|
});
|
|
10
10
|
};
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
11
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
-
exports.provisionRequest = void 0;
|
|
15
|
+
exports.createKeyPair = exports.provisionRequest = void 0;
|
|
13
16
|
/** Copyright © 2024-present P0 Security
|
|
14
17
|
|
|
15
18
|
This file is part of @p0security/cli
|
|
@@ -26,6 +29,7 @@ const request_1 = require("../types/request");
|
|
|
26
29
|
const request_2 = require("./request");
|
|
27
30
|
const firestore_2 = require("firebase/firestore");
|
|
28
31
|
const lodash_1 = require("lodash");
|
|
32
|
+
const node_forge_1 = __importDefault(require("node-forge"));
|
|
29
33
|
/** Maximum amount of time to wait after access is approved to wait for access
|
|
30
34
|
* to be configured
|
|
31
35
|
*/
|
|
@@ -100,3 +104,10 @@ const provisionRequest = (authn, args, destination) => __awaiter(void 0, void 0,
|
|
|
100
104
|
return id;
|
|
101
105
|
});
|
|
102
106
|
exports.provisionRequest = provisionRequest;
|
|
107
|
+
const createKeyPair = () => {
|
|
108
|
+
const rsaKeyPair = node_forge_1.default.pki.rsa.generateKeyPair({ bits: 2048 });
|
|
109
|
+
const privateKey = node_forge_1.default.pki.privateKeyToPem(rsaKeyPair.privateKey);
|
|
110
|
+
const publicKey = node_forge_1.default.ssh.publicKeyToOpenSSH(rsaKeyPair.publicKey);
|
|
111
|
+
return { publicKey, privateKey };
|
|
112
|
+
};
|
|
113
|
+
exports.createKeyPair = createKeyPair;
|
package/dist/commands/ssh.js
CHANGED
|
@@ -25,8 +25,6 @@ const auth_1 = require("../drivers/auth");
|
|
|
25
25
|
const firestore_1 = require("../drivers/firestore");
|
|
26
26
|
const ssm_1 = require("../plugins/aws/ssm");
|
|
27
27
|
const shared_1 = require("./shared");
|
|
28
|
-
// Matches strings with the pattern "digits:digits" (e.g. 1234:5678)
|
|
29
|
-
const LOCAL_PORT_FORWARD_PATTERN = /^\d+:\d+$/;
|
|
30
28
|
const sshCommand = (yargs) => yargs.command("ssh <destination> [command [arguments..]]", "SSH into a virtual machine", (yargs) => yargs
|
|
31
29
|
.positional("destination", {
|
|
32
30
|
type: "string",
|
|
@@ -45,22 +43,19 @@ const sshCommand = (yargs) => yargs.command("ssh <destination> [command [argumen
|
|
|
45
43
|
array: true,
|
|
46
44
|
string: true,
|
|
47
45
|
default: [],
|
|
48
|
-
})
|
|
49
|
-
.check((argv) => {
|
|
50
|
-
if (argv.L == null)
|
|
51
|
-
return true;
|
|
52
|
-
return (argv.L.match(LOCAL_PORT_FORWARD_PATTERN) ||
|
|
53
|
-
"Local port forward should be in the format `local_port:remote_port`");
|
|
54
46
|
})
|
|
55
47
|
.option("L", {
|
|
56
48
|
type: "string",
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
"Forward a local port to the remote host; `local_socket:remote_socket`",
|
|
49
|
+
// Copied from `man ssh`
|
|
50
|
+
describe: "Specifies that connections to the given TCP port or Unix socket on the local (client) host are to be forwarded to the given host and port, or Unix socket, on the remote side.",
|
|
60
51
|
})
|
|
61
52
|
.option("N", {
|
|
62
53
|
type: "boolean",
|
|
63
54
|
describe: "Do not execute a remote command. Useful for forwarding ports.",
|
|
55
|
+
})
|
|
56
|
+
.option("A", {
|
|
57
|
+
type: "boolean",
|
|
58
|
+
describe: "Enables forwarding of connections from an authentication agent such as ssh-agent",
|
|
64
59
|
})
|
|
65
60
|
// Match `p0 request --reason`
|
|
66
61
|
.option("reason", {
|
|
@@ -70,7 +65,11 @@ const sshCommand = (yargs) => yargs.command("ssh <destination> [command [argumen
|
|
|
70
65
|
.option("account", {
|
|
71
66
|
type: "string",
|
|
72
67
|
describe: "The account on which the instance is located",
|
|
73
|
-
})
|
|
68
|
+
})
|
|
69
|
+
.option("debug", {
|
|
70
|
+
type: "boolean",
|
|
71
|
+
describe: "Print debug information. The ssh-agent subprocess is not terminated automatically.",
|
|
72
|
+
}), (0, firestore_1.guard)(sshAction));
|
|
74
73
|
exports.sshCommand = sshCommand;
|
|
75
74
|
/** Connect to an SSH backend
|
|
76
75
|
*
|
|
@@ -79,7 +78,7 @@ exports.sshCommand = sshCommand;
|
|
|
79
78
|
* Supported SSH mechanisms:
|
|
80
79
|
* - AWS EC2 via SSM with Okta SAML
|
|
81
80
|
*/
|
|
82
|
-
const
|
|
81
|
+
const sshAction = (args) => __awaiter(void 0, void 0, void 0, function* () {
|
|
83
82
|
// Prefix is required because the backend uses it to determine that this is an AWS request
|
|
84
83
|
const authn = yield (0, auth_1.authenticate)();
|
|
85
84
|
const destination = args.destination;
|
|
@@ -87,9 +86,11 @@ const ssh = (args) => __awaiter(void 0, void 0, void 0, function* () {
|
|
|
87
86
|
if (!requestId) {
|
|
88
87
|
throw "Server did not return a request id. Please contact support@p0.dev for assistance.";
|
|
89
88
|
}
|
|
89
|
+
const { publicKey, privateKey } = (0, shared_1.createKeyPair)();
|
|
90
90
|
const result = yield (0, api_1.fetchExerciseGrant)(authn, {
|
|
91
91
|
requestId,
|
|
92
92
|
destination,
|
|
93
|
+
publicKey,
|
|
93
94
|
});
|
|
94
|
-
yield (0, ssm_1.
|
|
95
|
+
yield (0, ssm_1.sshOrScp)(authn, result, Object.assign(Object.assign({}, args), { destination }), privateKey);
|
|
95
96
|
});
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.main = void 0;
|
|
3
|
+
exports.main = exports.TERMINATION_CONTROLLER = void 0;
|
|
4
4
|
/** Copyright © 2024-present P0 Security
|
|
5
5
|
|
|
6
6
|
This file is part of @p0security/cli
|
|
@@ -13,6 +13,17 @@ You should have received a copy of the GNU General Public License along with @p0
|
|
|
13
13
|
**/
|
|
14
14
|
const commands_1 = require("./commands");
|
|
15
15
|
const lodash_1 = require("lodash");
|
|
16
|
+
const node_os_1 = require("node:os");
|
|
17
|
+
// Subscribing to this global abort controller allows handling process termination signals anywhere in the application
|
|
18
|
+
exports.TERMINATION_CONTROLLER = new AbortController();
|
|
19
|
+
const terminationHandler = (code) => () => {
|
|
20
|
+
exports.TERMINATION_CONTROLLER.abort(code);
|
|
21
|
+
process.exit(128 + code); // by convention the exit code is the signal code + 128
|
|
22
|
+
};
|
|
23
|
+
process.on("SIGHUP", terminationHandler(node_os_1.constants.signals.SIGHUP));
|
|
24
|
+
process.on("SIGINT", terminationHandler(node_os_1.constants.signals.SIGINT));
|
|
25
|
+
process.on("SIGQUIT", terminationHandler(node_os_1.constants.signals.SIGQUIT));
|
|
26
|
+
process.on("SIGTERM", terminationHandler(node_os_1.constants.signals.SIGTERM));
|
|
16
27
|
const main = () => {
|
|
17
28
|
// We can suppress output here, as .fail() already print1 errors
|
|
18
29
|
void commands_1.cli.parse().catch(lodash_1.noop);
|
|
@@ -10,6 +10,4 @@ You should have received a copy of the GNU General Public License along with @p0
|
|
|
10
10
|
**/
|
|
11
11
|
import { ExerciseGrantResponse, ScpCommandArgs, SshCommandArgs } from "../../../commands/shared";
|
|
12
12
|
import { Authn } from "../../../types/identity";
|
|
13
|
-
|
|
14
|
-
export declare const ssm: (authn: Authn, request: ExerciseGrantResponse, args: SshCommandArgs) => Promise<void>;
|
|
15
|
-
export declare const scp: (authn: Authn, data: ExerciseGrantResponse, args: ScpCommandArgs, privateKey: string) => Promise<number | null>;
|
|
13
|
+
export declare const sshOrScp: (authn: Authn, data: ExerciseGrantResponse, cmdArgs: ScpCommandArgs | SshCommandArgs, privateKey: string) => Promise<number | null>;
|