@automattic/vip 3.13.0 → 3.14.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/bin/vip-wp.js +9 -0
- package/dist/commands/wp-ssh.js +213 -0
- package/npm-shrinkwrap.json +16 -14
- package/package.json +3 -1
package/dist/bin/vip-wp.js
CHANGED
|
@@ -8,6 +8,7 @@ var _readline = _interopRequireDefault(require("readline"));
|
|
|
8
8
|
var _socket = _interopRequireDefault(require("socket.io-client"));
|
|
9
9
|
var _socket2 = _interopRequireDefault(require("socket.io-stream"));
|
|
10
10
|
var _stream = require("stream");
|
|
11
|
+
var _wpSsh = require("../commands/wp-ssh");
|
|
11
12
|
var _api = _interopRequireWildcard(require("../lib/api"));
|
|
12
13
|
var _command = _interopRequireWildcard(require("../lib/cli/command"));
|
|
13
14
|
var exit = _interopRequireWildcard(require("../lib/cli/exit"));
|
|
@@ -30,6 +31,7 @@ const appQuery = `id, name,
|
|
|
30
31
|
appId
|
|
31
32
|
type
|
|
32
33
|
name
|
|
34
|
+
wpcliStrategy
|
|
33
35
|
primaryDomain {
|
|
34
36
|
name
|
|
35
37
|
}
|
|
@@ -330,6 +332,13 @@ const examples = [{
|
|
|
330
332
|
(0, _api.disableGlobalGraphQLErrorHandling)();
|
|
331
333
|
const promptIdentifier = `${appName}.${(0, _command.getEnvIdentifier)(opts.env)}`;
|
|
332
334
|
let countSIGINT = 0;
|
|
335
|
+
if (opts.env.wpcliStrategy === 'ssh') {
|
|
336
|
+
const wpCommandRunner = new _wpSsh.WPCliCommandOverSSH(opts.app, opts.env);
|
|
337
|
+
await wpCommandRunner.run(cmd, {
|
|
338
|
+
command: commandForAnalytics
|
|
339
|
+
});
|
|
340
|
+
return;
|
|
341
|
+
}
|
|
333
342
|
const mutableStdout = new _stream.Writable({
|
|
334
343
|
write(chunk, encoding, callback) {
|
|
335
344
|
if (!this.muted) {
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
exports.__esModule = true;
|
|
4
|
+
exports.WPCliCommandOverSSH = exports.NonZeroExitCodeError = void 0;
|
|
5
|
+
var _chalk = _interopRequireDefault(require("chalk"));
|
|
6
|
+
var _debug = _interopRequireDefault(require("debug"));
|
|
7
|
+
var _graphqlTag = _interopRequireDefault(require("graphql-tag"));
|
|
8
|
+
var ssh2 = _interopRequireWildcard(require("ssh2"));
|
|
9
|
+
var _package = _interopRequireDefault(require("../../package.json"));
|
|
10
|
+
var _api = _interopRequireDefault(require("../lib/api"));
|
|
11
|
+
var _tracker = require("../lib/tracker");
|
|
12
|
+
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
|
13
|
+
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
|
14
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
15
|
+
/**
|
|
16
|
+
* External dependencies
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Internal dependencies
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
const debug = (0, _debug.default)('@automattic/vip:wp/ssh');
|
|
24
|
+
const NON_TTY_COLUMNS = 100;
|
|
25
|
+
const NON_TTY_ROWS = 15;
|
|
26
|
+
const SSH_HANDSHAKE_TIMEOUT_MS = 5000;
|
|
27
|
+
const TRIGGER_WP_CLI_COMMAND_MUTATION = (0, _graphqlTag.default)`
|
|
28
|
+
mutation TriggerWPCLICommandMutation($input: AppEnvironmentTriggerWPCLICommandInput) {
|
|
29
|
+
triggerWPCLICommandOnAppEnvironment(input: $input) {
|
|
30
|
+
inputToken
|
|
31
|
+
sshAuthentication {
|
|
32
|
+
host
|
|
33
|
+
port
|
|
34
|
+
username
|
|
35
|
+
privateKey
|
|
36
|
+
passphrase
|
|
37
|
+
}
|
|
38
|
+
command {
|
|
39
|
+
guid
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
`;
|
|
44
|
+
class NonZeroExitCodeError extends Error {
|
|
45
|
+
exitCode;
|
|
46
|
+
constructor(message, exitCode) {
|
|
47
|
+
super(message);
|
|
48
|
+
this.exitCode = exitCode;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
exports.NonZeroExitCodeError = NonZeroExitCodeError;
|
|
52
|
+
class WPCliCommandOverSSH {
|
|
53
|
+
app;
|
|
54
|
+
env;
|
|
55
|
+
track;
|
|
56
|
+
constructor(app, env) {
|
|
57
|
+
this.app = app;
|
|
58
|
+
this.env = env;
|
|
59
|
+
this.track = (0, _tracker.makeCommandTracker)('wp', {
|
|
60
|
+
app: this.app.id,
|
|
61
|
+
env: this.env.id,
|
|
62
|
+
execution_type: 'ssh'
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
async run(command, extraTrackingInfo = {}) {
|
|
66
|
+
if (!this.app.id || !this.env.id) {
|
|
67
|
+
await this.track('error', {
|
|
68
|
+
error: 'no_app_env_id',
|
|
69
|
+
message: 'No app or env ID provided',
|
|
70
|
+
...extraTrackingInfo
|
|
71
|
+
});
|
|
72
|
+
throw new Error('No app ID or environment ID provided');
|
|
73
|
+
}
|
|
74
|
+
debug("Requesting SSH authentication for command '%s'", command);
|
|
75
|
+
const sshAuth = await this.getSSHAuthForCommand(command, extraTrackingInfo);
|
|
76
|
+
const data = sshAuth.data?.triggerWPCLICommandOnAppEnvironment;
|
|
77
|
+
if (!data) {
|
|
78
|
+
await this.track('error', {
|
|
79
|
+
error: 'no_ssh_auth_data',
|
|
80
|
+
message: 'No SSH authentication data received',
|
|
81
|
+
...extraTrackingInfo
|
|
82
|
+
});
|
|
83
|
+
throw new Error('WP-CLI SSH Authentication failed');
|
|
84
|
+
}
|
|
85
|
+
debug('Connecting to SSH', {
|
|
86
|
+
host: data.sshAuthentication.host,
|
|
87
|
+
port: data.sshAuthentication.port,
|
|
88
|
+
username: data.sshAuthentication.username,
|
|
89
|
+
guid: data.command.guid
|
|
90
|
+
});
|
|
91
|
+
try {
|
|
92
|
+
await this.executeCommandOverSSH({
|
|
93
|
+
host: data.sshAuthentication.host,
|
|
94
|
+
port: data.sshAuthentication.port,
|
|
95
|
+
username: data.sshAuthentication.username,
|
|
96
|
+
privateKey: data.sshAuthentication.privateKey,
|
|
97
|
+
passphrase: data.sshAuthentication.passphrase,
|
|
98
|
+
guid: data.command.guid,
|
|
99
|
+
inputToken: data.inputToken
|
|
100
|
+
});
|
|
101
|
+
await this.track('success', {
|
|
102
|
+
guid: data?.command.guid
|
|
103
|
+
});
|
|
104
|
+
} catch (err) {
|
|
105
|
+
if (err instanceof NonZeroExitCodeError) {
|
|
106
|
+
await this.track('error', {
|
|
107
|
+
guid: data?.command.guid,
|
|
108
|
+
error: 'non_zero_exit_code',
|
|
109
|
+
message: `Command failed with exit code ${err.exitCode}`,
|
|
110
|
+
...extraTrackingInfo
|
|
111
|
+
});
|
|
112
|
+
process.exit(err.exitCode);
|
|
113
|
+
}
|
|
114
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
115
|
+
console.error(`${_chalk.default.red('Error:')} ${message}`);
|
|
116
|
+
await this.track('error', {
|
|
117
|
+
guid: data?.command.guid,
|
|
118
|
+
error: 'ssh_command_failed',
|
|
119
|
+
message: 'Error executing command over SSH',
|
|
120
|
+
...extraTrackingInfo
|
|
121
|
+
});
|
|
122
|
+
process.exit(1);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
async executeCommandOverSSH({
|
|
126
|
+
host,
|
|
127
|
+
port,
|
|
128
|
+
username,
|
|
129
|
+
privateKey,
|
|
130
|
+
passphrase,
|
|
131
|
+
guid,
|
|
132
|
+
inputToken
|
|
133
|
+
}) {
|
|
134
|
+
return new Promise((resolve, reject) => {
|
|
135
|
+
const conn = new ssh2.Client();
|
|
136
|
+
const columns = process.stdout.columns || NON_TTY_COLUMNS;
|
|
137
|
+
const rows = process.stdout.rows || NON_TTY_ROWS;
|
|
138
|
+
const isTTY = process.stdout.isTTY ? 'true' : 'false';
|
|
139
|
+
let commandStarted = false;
|
|
140
|
+
conn.on('ready', () => {
|
|
141
|
+
conn.exec(`GUID=${guid} INPUT_TOKEN=${inputToken} VERSION=${_package.default.version} ROWS=${rows} COLUMNS=${columns} TTY=${isTTY}`, (err, stream) => {
|
|
142
|
+
if (err) {
|
|
143
|
+
reject(err);
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
stream.on('exit', exitCode => {
|
|
147
|
+
if (exitCode !== 0) {
|
|
148
|
+
reject(new NonZeroExitCodeError(`Command failed`, exitCode));
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
commandStarted = true;
|
|
152
|
+
const handleSIGINT = () => {
|
|
153
|
+
process.removeListener('SIGINT', handleSIGINT);
|
|
154
|
+
console.log('SIGINT received. Canceling command...');
|
|
155
|
+
stream.end('\x03');
|
|
156
|
+
};
|
|
157
|
+
process.on('SIGINT', handleSIGINT);
|
|
158
|
+
const handleSIGTERM = () => {
|
|
159
|
+
process.removeListener('SIGTERM', handleSIGTERM);
|
|
160
|
+
console.log('SIGTERM received. Canceling command...');
|
|
161
|
+
stream.end('\x1F');
|
|
162
|
+
};
|
|
163
|
+
process.on('SIGTERM', handleSIGTERM);
|
|
164
|
+
stream.pipe(process.stdout);
|
|
165
|
+
process.stdin.pipe(stream);
|
|
166
|
+
stream.on('close', () => {
|
|
167
|
+
process.removeListener('SIGINT', handleSIGINT);
|
|
168
|
+
process.removeListener('SIGTERM', handleSIGTERM);
|
|
169
|
+
conn.end();
|
|
170
|
+
resolve();
|
|
171
|
+
});
|
|
172
|
+
});
|
|
173
|
+
}).on('error', err => {
|
|
174
|
+
reject(err);
|
|
175
|
+
}).on('close', () => {
|
|
176
|
+
if (!commandStarted) {
|
|
177
|
+
reject(new Error('Connection closed before command started'));
|
|
178
|
+
}
|
|
179
|
+
}).connect({
|
|
180
|
+
host,
|
|
181
|
+
port,
|
|
182
|
+
username,
|
|
183
|
+
privateKey,
|
|
184
|
+
passphrase,
|
|
185
|
+
readyTimeout: SSH_HANDSHAKE_TIMEOUT_MS
|
|
186
|
+
});
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
async getSSHAuthForCommand(command, extraTrackingInfo) {
|
|
190
|
+
const api = (0, _api.default)();
|
|
191
|
+
try {
|
|
192
|
+
return api.mutate({
|
|
193
|
+
mutation: TRIGGER_WP_CLI_COMMAND_MUTATION,
|
|
194
|
+
variables: {
|
|
195
|
+
input: {
|
|
196
|
+
id: this.app.id,
|
|
197
|
+
environmentId: this.env.id,
|
|
198
|
+
command
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
});
|
|
202
|
+
} catch (error) {
|
|
203
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
204
|
+
await this.track('error', {
|
|
205
|
+
error: 'trigger_failed',
|
|
206
|
+
message,
|
|
207
|
+
...extraTrackingInfo
|
|
208
|
+
});
|
|
209
|
+
throw new Error(`Unable to trigger the WP-CLI command`);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
exports.WPCliCommandOverSSH = WPCliCommandOverSSH;
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@automattic/vip",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.14.0",
|
|
4
4
|
"lockfileVersion": 2,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@automattic/vip",
|
|
9
|
-
"version": "3.
|
|
9
|
+
"version": "3.14.0",
|
|
10
10
|
"hasInstallScript": true,
|
|
11
11
|
"license": "MIT",
|
|
12
12
|
"dependencies": {
|
|
@@ -41,6 +41,7 @@
|
|
|
41
41
|
"socket.io-client": "^4.5.3",
|
|
42
42
|
"socket.io-stream": "npm:@wearemothership/socket.io-stream@^0.9.1",
|
|
43
43
|
"socks-proxy-agent": "^5.0.1",
|
|
44
|
+
"ssh2": "1.16.0",
|
|
44
45
|
"tar": "^7.4.0",
|
|
45
46
|
"update-notifier": "7.3.1",
|
|
46
47
|
"uuid": "11.1.0",
|
|
@@ -127,6 +128,7 @@
|
|
|
127
128
|
"@types/proxy-from-env": "^1.0.4",
|
|
128
129
|
"@types/semver": "^7.5.5",
|
|
129
130
|
"@types/shelljs": "^0.8.15",
|
|
131
|
+
"@types/ssh2": "^1.15.4",
|
|
130
132
|
"@types/tar": "^6.1.13",
|
|
131
133
|
"@types/update-notifier": "^6.0.8",
|
|
132
134
|
"@types/xml2js": "^0.4.14",
|
|
@@ -3797,9 +3799,9 @@
|
|
|
3797
3799
|
}
|
|
3798
3800
|
},
|
|
3799
3801
|
"node_modules/@types/ssh2": {
|
|
3800
|
-
"version": "1.
|
|
3801
|
-
"resolved": "https://registry.npmjs.org/@types/ssh2/-/ssh2-1.
|
|
3802
|
-
"integrity": "sha512-
|
|
3802
|
+
"version": "1.15.5",
|
|
3803
|
+
"resolved": "https://registry.npmjs.org/@types/ssh2/-/ssh2-1.15.5.tgz",
|
|
3804
|
+
"integrity": "sha512-N1ASjp/nXH3ovBHddRJpli4ozpk6UdDYIX4RJWFa9L1YKnzdhTlVmiGHm4DZnj/jLbqZpes4aeR30EFGQtvhQQ==",
|
|
3803
3805
|
"dev": true,
|
|
3804
3806
|
"dependencies": {
|
|
3805
3807
|
"@types/node": "^18.11.18"
|
|
@@ -5823,9 +5825,9 @@
|
|
|
5823
5825
|
}
|
|
5824
5826
|
},
|
|
5825
5827
|
"node_modules/dockerode": {
|
|
5826
|
-
"version": "4.0.
|
|
5827
|
-
"resolved": "https://registry.npmjs.org/dockerode/-/dockerode-4.0.
|
|
5828
|
-
"integrity": "sha512-
|
|
5828
|
+
"version": "4.0.6",
|
|
5829
|
+
"resolved": "https://registry.npmjs.org/dockerode/-/dockerode-4.0.6.tgz",
|
|
5830
|
+
"integrity": "sha512-FbVf3Z8fY/kALB9s+P9epCpWhfi/r0N2DgYYcYpsAUlaTxPjdsitsFobnltb+lyCgAIvf9C+4PSWlTnHlJMf1w==",
|
|
5829
5831
|
"license": "Apache-2.0",
|
|
5830
5832
|
"dependencies": {
|
|
5831
5833
|
"@balena/dockerignore": "^1.0.2",
|
|
@@ -16092,9 +16094,9 @@
|
|
|
16092
16094
|
}
|
|
16093
16095
|
},
|
|
16094
16096
|
"@types/ssh2": {
|
|
16095
|
-
"version": "1.
|
|
16096
|
-
"resolved": "https://registry.npmjs.org/@types/ssh2/-/ssh2-1.
|
|
16097
|
-
"integrity": "sha512-
|
|
16097
|
+
"version": "1.15.5",
|
|
16098
|
+
"resolved": "https://registry.npmjs.org/@types/ssh2/-/ssh2-1.15.5.tgz",
|
|
16099
|
+
"integrity": "sha512-N1ASjp/nXH3ovBHddRJpli4ozpk6UdDYIX4RJWFa9L1YKnzdhTlVmiGHm4DZnj/jLbqZpes4aeR30EFGQtvhQQ==",
|
|
16098
16100
|
"dev": true,
|
|
16099
16101
|
"requires": {
|
|
16100
16102
|
"@types/node": "^18.11.18"
|
|
@@ -17533,9 +17535,9 @@
|
|
|
17533
17535
|
}
|
|
17534
17536
|
},
|
|
17535
17537
|
"dockerode": {
|
|
17536
|
-
"version": "4.0.
|
|
17537
|
-
"resolved": "https://registry.npmjs.org/dockerode/-/dockerode-4.0.
|
|
17538
|
-
"integrity": "sha512-
|
|
17538
|
+
"version": "4.0.6",
|
|
17539
|
+
"resolved": "https://registry.npmjs.org/dockerode/-/dockerode-4.0.6.tgz",
|
|
17540
|
+
"integrity": "sha512-FbVf3Z8fY/kALB9s+P9epCpWhfi/r0N2DgYYcYpsAUlaTxPjdsitsFobnltb+lyCgAIvf9C+4PSWlTnHlJMf1w==",
|
|
17539
17541
|
"requires": {
|
|
17540
17542
|
"@balena/dockerignore": "^1.0.2",
|
|
17541
17543
|
"@grpc/grpc-js": "^1.11.1",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@automattic/vip",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.14.0",
|
|
4
4
|
"description": "The VIP Javascript library & CLI",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
@@ -127,6 +127,7 @@
|
|
|
127
127
|
"@types/proxy-from-env": "^1.0.4",
|
|
128
128
|
"@types/semver": "^7.5.5",
|
|
129
129
|
"@types/shelljs": "^0.8.15",
|
|
130
|
+
"@types/ssh2": "^1.15.4",
|
|
130
131
|
"@types/tar": "^6.1.13",
|
|
131
132
|
"@types/update-notifier": "^6.0.8",
|
|
132
133
|
"@types/xml2js": "^0.4.14",
|
|
@@ -170,6 +171,7 @@
|
|
|
170
171
|
"socket.io-client": "^4.5.3",
|
|
171
172
|
"socket.io-stream": "npm:@wearemothership/socket.io-stream@^0.9.1",
|
|
172
173
|
"socks-proxy-agent": "^5.0.1",
|
|
174
|
+
"ssh2": "1.16.0",
|
|
173
175
|
"tar": "^7.4.0",
|
|
174
176
|
"update-notifier": "7.3.1",
|
|
175
177
|
"uuid": "11.1.0",
|