ssh-client-wrapper 2.11.0 → 2.12.4
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/.github/workflows/coverage_report.yml +1 -1
- package/.github/workflows/run_test.yml +3 -2
- package/eslint.config.mjs +206 -0
- package/lib/fork.js +25 -13
- package/lib/index.js +63 -16
- package/lib/rsyncExec.js +17 -17
- package/lib/sshExec.js +69 -59
- package/lib/util.js +25 -21
- package/package.json +10 -12
- package/test/getSshOption.js +7 -7
- package/test/interface.js +54 -54
- package/test/rsyncExec.js +72 -72
- package/test/sanityCheck.js +14 -14
- package/test/sshExec.js +34 -66
- package/test/testUtil/testFiles.js +21 -7
package/lib/sshExec.js
CHANGED
|
@@ -3,20 +3,25 @@ const crypto = require("crypto");
|
|
|
3
3
|
const { setTimeout: setTimeoutPromise } = require("timers/promises");
|
|
4
4
|
const debug = require("debug")("sshClientWrapper:debug:sshExec");
|
|
5
5
|
const debugVerbose = require("debug")("sshClientWrapper:verbose:sshExec");
|
|
6
|
-
const debugSendMasterPty = require("debug")("
|
|
6
|
+
const debugSendMasterPty = require("debug")("sshClientWrapper:insecure:sshExec:masterPty");
|
|
7
7
|
const { sendPty, sshCmd, getSshOption, sanityCheck, watchDogTimer } = require("./util.js");
|
|
8
8
|
const { fork, createMasterPty, sshLoginCallback } = require("./fork.js");
|
|
9
9
|
|
|
10
|
+
/**
|
|
11
|
+
* @typedef Integer {number} - integer number
|
|
12
|
+
*/
|
|
13
|
+
|
|
10
14
|
/**
|
|
11
15
|
* Execute command on remote host.
|
|
12
|
-
* @param {
|
|
16
|
+
* @param {object} hostInfo - hostinfo object
|
|
13
17
|
* @param {string} cmd - Cmdline which will be executed on remote host.
|
|
14
18
|
* @param {number} timeout - timeout (in sec.)
|
|
19
|
+
* @param {Function} outputCallback - Callback routine for stdout and stderr.
|
|
15
20
|
* @param {string} rcfile - rcfile path which will be sourced before executing actual command
|
|
16
21
|
* @param {string} prependCmd - command string which will be executed before executing actual command
|
|
17
|
-
* @
|
|
22
|
+
* @returns {Integer} - return value of cmd
|
|
18
23
|
*/
|
|
19
|
-
async function sshExec
|
|
24
|
+
async function sshExec(hostInfo, cmd, timeout, outputCallback, rcfile, prependCmd) {
|
|
20
25
|
debug("sshExec called");
|
|
21
26
|
await connect(hostInfo);
|
|
22
27
|
debug("exec", cmd, "on remote server");
|
|
@@ -44,11 +49,42 @@ async function sshExec (hostInfo, cmd, timeout, outputCallback, rcfile, prependC
|
|
|
44
49
|
}
|
|
45
50
|
if (e.rt === 126) {
|
|
46
51
|
debug(`${cmd} got Permission deny error but ignored`);
|
|
47
|
-
return e.rt;
|
|
48
52
|
}
|
|
49
53
|
if (e.rt === 127) {
|
|
50
54
|
debug(`${cmd} not found but ignored`);
|
|
51
|
-
|
|
55
|
+
}
|
|
56
|
+
return e.rt;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
async function expect(hostInfo, cmd, expects, timeout) {
|
|
61
|
+
debug("expect called");
|
|
62
|
+
await connect(hostInfo);
|
|
63
|
+
debugVerbose("exec", cmd, "on remote server with", expects);
|
|
64
|
+
const args = getSshOption(hostInfo, false);
|
|
65
|
+
const compiledExpects = expects.map((e)=>{
|
|
66
|
+
return {
|
|
67
|
+
reExpect: new RegExp(e.expect),
|
|
68
|
+
send: e.send,
|
|
69
|
+
keep: e.keep
|
|
70
|
+
};
|
|
71
|
+
});
|
|
72
|
+
const reExpect = hostInfo.prompt ? new RegExp(hostInfo.prompt) : /[$#>] /;
|
|
73
|
+
compiledExpects.unshift({ reExpect, send: cmd });
|
|
74
|
+
compiledExpects.push({ reExpect, send: "exit" });
|
|
75
|
+
|
|
76
|
+
try {
|
|
77
|
+
const rt = await fork(hostInfo, sshCmd, args, timeout, null, [], compiledExpects);
|
|
78
|
+
return rt;
|
|
79
|
+
} catch (e) {
|
|
80
|
+
if (typeof e.rt === "undefined") {
|
|
81
|
+
throw e;
|
|
82
|
+
}
|
|
83
|
+
if (e.rt === 126) {
|
|
84
|
+
debug(`${cmd} got Permission deny error but ignored`);
|
|
85
|
+
}
|
|
86
|
+
if (e.rt === 127) {
|
|
87
|
+
debug(`${cmd} not found but ignored`);
|
|
52
88
|
}
|
|
53
89
|
return e.rt;
|
|
54
90
|
}
|
|
@@ -56,32 +92,32 @@ async function sshExec (hostInfo, cmd, timeout, outputCallback, rcfile, prependC
|
|
|
56
92
|
|
|
57
93
|
/**
|
|
58
94
|
* Check if you can connect to sepecified server
|
|
59
|
-
* @param {
|
|
95
|
+
* @param {object} hostInfo - hostinfo object
|
|
60
96
|
* @param {Integer} timeout - timeout in secconds
|
|
61
97
|
*/
|
|
62
|
-
async function canConnect
|
|
98
|
+
async function canConnect(hostInfo, timeout) {
|
|
63
99
|
debug("canConnect called");
|
|
64
100
|
sanityCheck(hostInfo);
|
|
65
101
|
|
|
66
102
|
await connect(hostInfo, timeout);
|
|
67
103
|
await disconnect(hostInfo);
|
|
68
|
-
//
|
|
69
|
-
//
|
|
104
|
+
//if connection fail, Error is throwed.
|
|
105
|
+
//so, if we reach here, connection must be succeeded
|
|
70
106
|
return true;
|
|
71
107
|
}
|
|
72
108
|
|
|
73
109
|
/**
|
|
74
110
|
* check if master session exists or not
|
|
75
|
-
* @param {
|
|
111
|
+
* @param {object} hostInfo - hostinfo object
|
|
76
112
|
* @returns {boolean} - true if master session exists
|
|
77
113
|
*/
|
|
78
|
-
async function existsMaster
|
|
114
|
+
async function existsMaster(hostInfo, argTimeout) {
|
|
79
115
|
debugVerbose("existsMaster called");
|
|
80
116
|
const args = getSshOption(hostInfo);
|
|
81
117
|
args.push("-Ocheck");
|
|
82
118
|
|
|
83
119
|
let output = "";
|
|
84
|
-
const cb = (e)
|
|
120
|
+
const cb = (e)=>{
|
|
85
121
|
output += e;
|
|
86
122
|
};
|
|
87
123
|
|
|
@@ -105,9 +141,9 @@ async function existsMaster (hostInfo, argTimeout) {
|
|
|
105
141
|
|
|
106
142
|
/**
|
|
107
143
|
* create master ssh connection
|
|
108
|
-
* @param {
|
|
144
|
+
* @param {object} hostInfo - hostinfo object
|
|
109
145
|
*/
|
|
110
|
-
async function connect
|
|
146
|
+
async function connect(hostInfo, timeout = 60) {
|
|
111
147
|
debug("connect called");
|
|
112
148
|
|
|
113
149
|
if (await existsMaster(hostInfo, timeout)) {
|
|
@@ -123,8 +159,9 @@ async function connect (hostInfo, timeout = 60) {
|
|
|
123
159
|
const re = new RegExp(`^${words}`);
|
|
124
160
|
|
|
125
161
|
let ac = null;
|
|
126
|
-
|
|
127
|
-
|
|
162
|
+
let output = null;
|
|
163
|
+
const p = new Promise((resolve, reject)=>{
|
|
164
|
+
ac = watchDogTimer(timeout, "make connection", ()=>{
|
|
128
165
|
sendPty(hostInfo.masterPty, "\n", debugSendMasterPty, 137);
|
|
129
166
|
sendPty(hostInfo.masterPty, "exit\n", debugSendMasterPty, 138);
|
|
130
167
|
|
|
@@ -132,16 +169,17 @@ async function connect (hostInfo, timeout = 60) {
|
|
|
132
169
|
err.host = hostInfo.host;
|
|
133
170
|
err.user = hostInfo.user;
|
|
134
171
|
err.port = hostInfo.port;
|
|
172
|
+
err.output = output;
|
|
135
173
|
reject(err);
|
|
136
174
|
});
|
|
137
175
|
|
|
138
176
|
let done = false;
|
|
139
|
-
hostInfo.masterPty.onData((data)
|
|
177
|
+
hostInfo.masterPty.onData((data)=>{
|
|
140
178
|
if (done) {
|
|
141
|
-
//
|
|
179
|
+
//safeguard
|
|
142
180
|
return;
|
|
143
181
|
}
|
|
144
|
-
|
|
182
|
+
output = data.toString();
|
|
145
183
|
debugVerbose(output);
|
|
146
184
|
|
|
147
185
|
if (re.test(output)) {
|
|
@@ -160,12 +198,12 @@ async function connect (hostInfo, timeout = 60) {
|
|
|
160
198
|
reject(new Error("Control socket creation failed"));
|
|
161
199
|
}
|
|
162
200
|
});
|
|
163
|
-
hostInfo.masterPty.onData((data)
|
|
201
|
+
hostInfo.masterPty.onData((data)=>{
|
|
164
202
|
const output = data.toString();
|
|
165
203
|
sshLoginCallback(output, hostInfo.masterPty, hostInfo.password, hostInfo.passphrase, debugSendMasterPty)
|
|
166
204
|
.catch(reject);
|
|
167
205
|
});
|
|
168
|
-
hostInfo.masterPty.onExit((e)
|
|
206
|
+
hostInfo.masterPty.onExit((e)=>{
|
|
169
207
|
debug("master pty exit", e);
|
|
170
208
|
resolve(e);
|
|
171
209
|
});
|
|
@@ -188,9 +226,9 @@ async function connect (hostInfo, timeout = 60) {
|
|
|
188
226
|
|
|
189
227
|
/**
|
|
190
228
|
* remove master session
|
|
191
|
-
* @param {
|
|
229
|
+
* @param {object} hostInfo - hostinfo object
|
|
192
230
|
*/
|
|
193
|
-
async function disconnect
|
|
231
|
+
async function disconnect(hostInfo) {
|
|
194
232
|
debug("disconnect called");
|
|
195
233
|
|
|
196
234
|
if (await existsMaster(hostInfo)) {
|
|
@@ -198,7 +236,7 @@ async function disconnect (hostInfo) {
|
|
|
198
236
|
args.push("-Oexit");
|
|
199
237
|
|
|
200
238
|
let output = "";
|
|
201
|
-
const cb = (e)
|
|
239
|
+
const cb = (e)=>{
|
|
202
240
|
output += e;
|
|
203
241
|
};
|
|
204
242
|
try {
|
|
@@ -225,50 +263,22 @@ async function disconnect (hostInfo) {
|
|
|
225
263
|
}
|
|
226
264
|
}
|
|
227
265
|
|
|
228
|
-
/**
|
|
229
|
-
* execute ls command and return output
|
|
230
|
-
* @param {Object} hostInfo - hostinfo object
|
|
231
|
-
* @param {string} target - file or directory path to watch
|
|
232
|
-
* @param {string[]} lsOpt - optional arguments for ls
|
|
233
|
-
* @param {number} timeout - timeout (in sec.)
|
|
234
|
-
* @returns {string[]} - output from ls
|
|
235
|
-
*/
|
|
236
|
-
async function ls (hostInfo, target, lsOpt, timeout) {
|
|
237
|
-
debug("ls called");
|
|
238
|
-
const outputArray = [];
|
|
239
|
-
try {
|
|
240
|
-
await sshExec(hostInfo, `ls ${lsOpt.join(" ")} ${target}`, timeout, (data) => {
|
|
241
|
-
outputArray.push(data);
|
|
242
|
-
});
|
|
243
|
-
} catch (e) {
|
|
244
|
-
// non-zero retrun should be allowed
|
|
245
|
-
if (typeof e.rt === "undefined" || e.rt < 0) {
|
|
246
|
-
throw e;
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
return outputArray.length === 0
|
|
250
|
-
? []
|
|
251
|
-
: outputArray
|
|
252
|
-
.join("\n")
|
|
253
|
-
.replace(/\n+/g, "\n")
|
|
254
|
-
.replace(/\n$/, "")
|
|
255
|
-
.split("\n");
|
|
256
|
-
}
|
|
257
|
-
|
|
258
266
|
/**
|
|
259
267
|
* retry fork() if it throw retryable error
|
|
260
268
|
* @param {Function} func - function to be wrapped
|
|
261
|
-
* @param {
|
|
269
|
+
* @param {object} hostInfo - hostinfo object
|
|
262
270
|
* @param {Integer} argMaxRetry - max retry number
|
|
271
|
+
* @param {Integer} argDuration - time to wait before retring
|
|
272
|
+
* @returns {Integer} - return value of func
|
|
263
273
|
*/
|
|
264
|
-
async function retryWrapper
|
|
274
|
+
async function retryWrapper(func, hostInfo, argMaxRetry, argDuration) {
|
|
265
275
|
const maxRetry = argMaxRetry || hostInfo.maxRetry || 3;
|
|
266
276
|
const duration = argDuration || hostInfo.retryDuration || 1000;
|
|
267
277
|
if (maxRetry === 1) {
|
|
268
278
|
return func();
|
|
269
279
|
}
|
|
270
280
|
let retryCount = 0;
|
|
271
|
-
|
|
281
|
+
for (;;) {
|
|
272
282
|
let rt;
|
|
273
283
|
try {
|
|
274
284
|
rt = await func();
|
|
@@ -297,6 +307,6 @@ module.exports = {
|
|
|
297
307
|
canConnect,
|
|
298
308
|
connect,
|
|
299
309
|
disconnect,
|
|
300
|
-
|
|
310
|
+
expect,
|
|
301
311
|
retryWrapper
|
|
302
312
|
};
|
package/lib/util.js
CHANGED
|
@@ -26,7 +26,7 @@ const ajv = new Ajv({
|
|
|
26
26
|
});
|
|
27
27
|
require("ajv-keywords")(ajv, "transform");
|
|
28
28
|
|
|
29
|
-
//
|
|
29
|
+
//never validate password and passphrase value to avoid security insident
|
|
30
30
|
const hostInfoSchema = {
|
|
31
31
|
type: "object",
|
|
32
32
|
properties: {
|
|
@@ -42,7 +42,11 @@ const hostInfoSchema = {
|
|
|
42
42
|
retryDuration: { type: "number", minimum: 0, default: 1000 },
|
|
43
43
|
rcfile: { type: "string", pattern: "\\S+", transform: ["trim"] },
|
|
44
44
|
prependCmd: { type: "string", pattern: "\\S+", transform: ["trim"] },
|
|
45
|
-
sshOpt: {
|
|
45
|
+
sshOpt: {
|
|
46
|
+
type: "array",
|
|
47
|
+
minItems: 1,
|
|
48
|
+
items: { type: "string", pattern: "\\S+", transform: ["trim"] }
|
|
49
|
+
}
|
|
46
50
|
},
|
|
47
51
|
required: ["host"]
|
|
48
52
|
};
|
|
@@ -66,20 +70,20 @@ const validate = ajv.compile(hostInfoSchema);
|
|
|
66
70
|
* @param {Function} func - function
|
|
67
71
|
* @param {data} data - binary data which can be converted to string
|
|
68
72
|
*/
|
|
69
|
-
const buff2String = (func, data)
|
|
73
|
+
const buff2String = (func, data)=>{
|
|
70
74
|
func(data.toString().replace(/\r\n/g, EOL));
|
|
71
75
|
};
|
|
72
76
|
|
|
73
77
|
/**
|
|
74
78
|
* check if given hostInfo object is OK
|
|
75
|
-
* @param {
|
|
79
|
+
* @param {object} hostInfo - host information object defined in index.js
|
|
76
80
|
*/
|
|
77
|
-
const sanityCheck = (hostInfo)
|
|
81
|
+
const sanityCheck = (hostInfo)=>{
|
|
78
82
|
debug("sanityCheck called", hostInfo);
|
|
79
83
|
|
|
80
|
-
//
|
|
81
|
-
//
|
|
82
|
-
//
|
|
84
|
+
//keep password, passphrase, and masterPty before validate.
|
|
85
|
+
//these properties can have a iellegal value as JSON data
|
|
86
|
+
//so we keep them before ajv validation and put them back
|
|
83
87
|
|
|
84
88
|
const { password, passphrase, masterPty } = hostInfo;
|
|
85
89
|
validate(hostInfo);
|
|
@@ -102,7 +106,7 @@ const sanityCheck = (hostInfo) => {
|
|
|
102
106
|
}
|
|
103
107
|
if (prop.startsWith("sshOpt")) {
|
|
104
108
|
debug("remove empty member of sshOpt");
|
|
105
|
-
hostInfo.sshOpt = hostInfo.sshOpt.filter((opt)
|
|
109
|
+
hostInfo.sshOpt = hostInfo.sshOpt.filter((opt)=>{
|
|
106
110
|
return opt !== "";
|
|
107
111
|
});
|
|
108
112
|
continue;
|
|
@@ -134,7 +138,7 @@ const sanityCheck = (hostInfo) => {
|
|
|
134
138
|
return hostInfo;
|
|
135
139
|
};
|
|
136
140
|
|
|
137
|
-
function getControlPersistDir
|
|
141
|
+
function getControlPersistDir(hostInfo) {
|
|
138
142
|
for (const candidate of [hostInfo.ControlPersistDir, process.env.SSH_CONTROL_PERSIST_DIR]) {
|
|
139
143
|
if (typeof candidate === "string") {
|
|
140
144
|
const stat = fs.statSync(candidate, { throwIfNoEntry: false });
|
|
@@ -148,10 +152,10 @@ function getControlPersistDir (hostInfo) {
|
|
|
148
152
|
|
|
149
153
|
/**
|
|
150
154
|
* return ssh option with some hard corded options
|
|
151
|
-
* @param {
|
|
155
|
+
* @param {object} hostInfo - host information object defined in index.js
|
|
152
156
|
* @param {boolean} withoutDestination - return except for hostname
|
|
153
157
|
*/
|
|
154
|
-
const getSshOption = (hostInfo, withoutDestination)
|
|
158
|
+
const getSshOption = (hostInfo, withoutDestination)=>{
|
|
155
159
|
debug("getSshOption called");
|
|
156
160
|
const args = [];
|
|
157
161
|
|
|
@@ -205,7 +209,7 @@ const getSshOption = (hostInfo, withoutDestination) => {
|
|
|
205
209
|
args.push(`-oConnectTimeout=${hostInfo.ConnectTimeout}`);
|
|
206
210
|
}
|
|
207
211
|
if (Array.isArray(hostInfo.sshOpt)) {
|
|
208
|
-
args.push(...hostInfo.sshOpt.filter((e)
|
|
212
|
+
args.push(...hostInfo.sshOpt.filter((e)=>{
|
|
209
213
|
return typeof e === "string";
|
|
210
214
|
}));
|
|
211
215
|
}
|
|
@@ -213,24 +217,24 @@ const getSshOption = (hostInfo, withoutDestination) => {
|
|
|
213
217
|
return args;
|
|
214
218
|
};
|
|
215
219
|
|
|
216
|
-
const isArrayOfString = (target)
|
|
220
|
+
const isArrayOfString = (target)=>{
|
|
217
221
|
if (!Array.isArray(target)) {
|
|
218
222
|
return false;
|
|
219
223
|
}
|
|
220
|
-
return !target.some((e)
|
|
221
|
-
//
|
|
224
|
+
return !target.some((e)=>{
|
|
225
|
+
//target has non string member
|
|
222
226
|
return typeof e !== "string";
|
|
223
227
|
});
|
|
224
228
|
};
|
|
225
229
|
|
|
226
230
|
/**
|
|
227
231
|
* log and send message to pty
|
|
228
|
-
* @param {
|
|
232
|
+
* @param {object} pty - pty object which message will be send to
|
|
229
233
|
* @param {string} message - message
|
|
230
234
|
* @param {Function} logger - logging function
|
|
231
235
|
* @param {string} label - where this function is called
|
|
232
236
|
*/
|
|
233
|
-
const sendPty = async (pty, message, logger, label)
|
|
237
|
+
const sendPty = async (pty, message, logger, label)=>{
|
|
234
238
|
logger(`${label}: ${message}`);
|
|
235
239
|
pty.write(message);
|
|
236
240
|
};
|
|
@@ -242,15 +246,15 @@ const sendPty = async (pty, message, logger, label) => {
|
|
|
242
246
|
* @param {Function} cb - call back function which will be called after timeout
|
|
243
247
|
* @returns {AbortController} - ac to stop watch dog timer
|
|
244
248
|
*/
|
|
245
|
-
const watchDogTimer = (timeout, label, cb)
|
|
249
|
+
const watchDogTimer = (timeout, label, cb)=>{
|
|
246
250
|
const ac = new AbortController();
|
|
247
251
|
const signal = ac.signal;
|
|
248
252
|
setTimeoutPromise(timeout * 1000, "neverUsedValue", { signal })
|
|
249
|
-
.then(()
|
|
253
|
+
.then(()=>{
|
|
250
254
|
debug(`can not finish ${label} within ${timeout} sec`);
|
|
251
255
|
return typeof cb === "function" ? cb() : true;
|
|
252
256
|
})
|
|
253
|
-
.catch((err)
|
|
257
|
+
.catch((err)=>{
|
|
254
258
|
if (err.name === "AbortError") {
|
|
255
259
|
debug(`timeout was aborted because ${label} has finished or canceled`);
|
|
256
260
|
} else {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ssh-client-wrapper",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.12.4",
|
|
4
4
|
"description": "wrapper library for open ssh client and rsync",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ssh",
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"main": "lib/index.js",
|
|
15
15
|
"scripts": {
|
|
16
16
|
"mocha": "mocha --recursive test",
|
|
17
|
-
"lint": "eslint --fix
|
|
17
|
+
"lint": "eslint --fix ./",
|
|
18
18
|
"test": "nyc --reporter=html --reporter=text mocha",
|
|
19
19
|
"coverage": "nyc report --reporter=text-lcov > coverage-report.lcov",
|
|
20
20
|
"postversion": "git push && git push origin $(git describe --abbrev=0 --tags)",
|
|
@@ -34,24 +34,22 @@
|
|
|
34
34
|
"*.js": "eslint --fix"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"ajv": "^8.
|
|
37
|
+
"ajv": "^8.17.1",
|
|
38
38
|
"ajv-keywords": "^5.1.0",
|
|
39
|
-
"debug": "^4.
|
|
40
|
-
"
|
|
39
|
+
"debug": "^4.4.0",
|
|
40
|
+
"eslint-plugin-chai-friendly": "^1.0.1",
|
|
41
|
+
"glob": "^10.4.5",
|
|
41
42
|
"node-pty": "^0.10.1",
|
|
42
43
|
"promise-retry": "^2.0.1"
|
|
43
44
|
},
|
|
44
45
|
"devDependencies": {
|
|
46
|
+
"@eslint/js": "^9.19.0",
|
|
47
|
+
"@stylistic/eslint-plugin": "^3.0.1",
|
|
45
48
|
"chai": "^4.3.7",
|
|
46
49
|
"chai-as-promised": "^7.1.1",
|
|
47
50
|
"chai-fs": "^2.0.0",
|
|
48
|
-
"eslint": "^
|
|
49
|
-
"eslint-
|
|
50
|
-
"eslint-plugin-chai-expect": "^3.0.0",
|
|
51
|
-
"eslint-plugin-chai-friendly": "^0.7.4",
|
|
52
|
-
"eslint-plugin-import": "^2.29.1",
|
|
53
|
-
"eslint-plugin-n": "^16.6.2",
|
|
54
|
-
"eslint-plugin-promise": "^6.1.1",
|
|
51
|
+
"eslint-plugin-jsdoc": "^50.6.3",
|
|
52
|
+
"eslint-plugin-node": "^11.1.0",
|
|
55
53
|
"fs-extra": "^11.1.1",
|
|
56
54
|
"husky": "^8.0.0",
|
|
57
55
|
"lint-staged": "^13.2.1",
|
package/test/getSshOption.js
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
process.on("unhandledRejection", console.dir); //
|
|
2
|
+
process.on("unhandledRejection", console.dir); //eslint-disable-line no-console
|
|
3
3
|
|
|
4
|
-
//
|
|
4
|
+
//setup test framework
|
|
5
5
|
const chai = require("chai");
|
|
6
6
|
const { expect } = require("chai");
|
|
7
7
|
chai.use(require("chai-as-promised"));
|
|
8
8
|
|
|
9
|
-
//
|
|
9
|
+
//testee
|
|
10
10
|
const { getSshOption } = require("../lib/util.js");
|
|
11
11
|
|
|
12
|
-
describe("test for getSshOption", ()
|
|
12
|
+
describe("test for getSshOption", ()=>{
|
|
13
13
|
const defaultValues = {
|
|
14
14
|
host: "testHostName",
|
|
15
15
|
ControlPersist: 180,
|
|
16
16
|
maxRetry: 3,
|
|
17
17
|
retryDuration: 1000
|
|
18
18
|
};
|
|
19
|
-
it("should return minimum ssh option array", ()
|
|
19
|
+
it("should return minimum ssh option array", ()=>{
|
|
20
20
|
const sshOpts = getSshOption(defaultValues);
|
|
21
21
|
expect(sshOpts).to.be.an("array");
|
|
22
22
|
expect(sshOpts).to.have.lengthOf(4);
|
|
@@ -25,7 +25,7 @@ describe("test for getSshOption", () => {
|
|
|
25
25
|
expect(sshOpts[2]).to.equal("-oControlPath=~/.ssh/ssh-client-wrapper-%r@%h:%p");
|
|
26
26
|
expect(sshOpts[3]).to.equal("-oControlPersist=180");
|
|
27
27
|
});
|
|
28
|
-
it("should change ControlPath by ControlPersistDir", ()
|
|
28
|
+
it("should change ControlPath by ControlPersistDir", ()=>{
|
|
29
29
|
const hostInfo = { ...defaultValues };
|
|
30
30
|
hostInfo.ControlPersistDir = "/tmp";
|
|
31
31
|
const sshOpts = getSshOption(hostInfo);
|
|
@@ -36,7 +36,7 @@ describe("test for getSshOption", () => {
|
|
|
36
36
|
expect(sshOpts[2]).to.equal("-oControlPath=/tmp/ssh-client-wrapper-%r@%h:%p");
|
|
37
37
|
expect(sshOpts[3]).to.equal("-oControlPersist=180");
|
|
38
38
|
});
|
|
39
|
-
it("should change ControlPath by Environment variable", ()
|
|
39
|
+
it("should change ControlPath by Environment variable", ()=>{
|
|
40
40
|
process.env.SSH_CONTROL_PERSIST_DIR = "/tmp";
|
|
41
41
|
const sshOpts = getSshOption(defaultValues);
|
|
42
42
|
expect(sshOpts).to.be.an("array");
|