@automattic/vip 2.36.3 → 2.37.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/assets/dev-env.lando.template.yml.ejs +1 -1
- package/dist/bin/vip-app-deploy.js +251 -0
- package/dist/bin/vip-app.js +1 -1
- package/dist/bin/vip-dev-env-import-sql.js +1 -1
- package/dist/bin/vip-import-sql.js +1 -1
- package/dist/commands/dev-env-import-sql.js +18 -15
- package/dist/commands/dev-env-sync-sql.js +3 -2
- package/dist/lib/cli/command.js +28 -19
- package/dist/lib/cli/exit.js +7 -2
- package/dist/lib/cli/format.js +2 -2
- package/dist/lib/client-file-uploader.js +22 -13
- package/dist/lib/constants/dev-environment.js +2 -10
- package/dist/lib/custom-deploy/custom-deploy.js +95 -0
- package/dist/lib/dev-environment/dev-environment-cli.js +4 -2
- package/dist/lib/dev-environment/dev-environment-configuration-file.js +7 -6
- package/dist/lib/dev-environment/dev-environment-core.js +20 -7
- package/dist/lib/dev-environment/docker-utils.js +1 -1
- package/dist/lib/env.js +2 -1
- package/dist/lib/user-error.js +2 -2
- package/dist/lib/validations/custom-deploy.js +39 -0
- package/dist/lib/validations/line-by-line.js +3 -1
- package/dist/lib/validations/sql.js +1 -1
- package/docs/CHANGELOG.md +44 -0
- package/npm-shrinkwrap.json +346 -698
- package/package.json +7 -5
- package/tsconfig.json +2 -2
|
@@ -29,15 +29,7 @@ const DEV_ENVIRONMENT_PHP_VERSIONS = exports.DEV_ENVIRONMENT_PHP_VERSIONS = {
|
|
|
29
29
|
},
|
|
30
30
|
8.3: {
|
|
31
31
|
image: 'ghcr.io/automattic/vip-container-images/php-fpm:8.3',
|
|
32
|
-
label: '8.3
|
|
33
|
-
},
|
|
34
|
-
'8.0': {
|
|
35
|
-
image: 'ghcr.io/automattic/vip-container-images/php-fpm:8.0',
|
|
36
|
-
label: '8.0 (EOL soon)'
|
|
37
|
-
},
|
|
38
|
-
7.4: {
|
|
39
|
-
image: 'ghcr.io/automattic/vip-container-images/php-fpm:7.4',
|
|
40
|
-
label: '7.4 (EOL; not supported)'
|
|
32
|
+
label: '8.3'
|
|
41
33
|
}
|
|
42
34
|
};
|
|
43
|
-
const DEV_ENVIRONMENT_VERSION = exports.DEV_ENVIRONMENT_VERSION = '2.0.
|
|
35
|
+
const DEV_ENVIRONMENT_VERSION = exports.DEV_ENVIRONMENT_VERSION = '2.0.2';
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
exports.__esModule = true;
|
|
4
|
+
exports.gates = gates;
|
|
5
|
+
exports.isSupportedApp = isSupportedApp;
|
|
6
|
+
var _fs = _interopRequireDefault(require("fs"));
|
|
7
|
+
var exit = _interopRequireWildcard(require("../../lib/cli/exit"));
|
|
8
|
+
var _clientFileUploader = require("../../lib/client-file-uploader");
|
|
9
|
+
var _fileSize = require("../../lib/constants/file-size");
|
|
10
|
+
var _vipgo = require("../../lib/constants/vipgo");
|
|
11
|
+
var _tracker = require("../../lib/tracker");
|
|
12
|
+
var _customDeploy = require("../../lib/validations/custom-deploy");
|
|
13
|
+
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); }
|
|
14
|
+
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 && Object.prototype.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; }
|
|
15
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
16
|
+
const DEPLOY_MAX_FILE_SIZE = 4 * _fileSize.GB_IN_BYTES;
|
|
17
|
+
function isSupportedApp(app) {
|
|
18
|
+
return _vipgo.WORDPRESS_SITE_TYPE_IDS.includes(app.typeId);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* @param {FileMeta} fileMeta
|
|
23
|
+
*/
|
|
24
|
+
async function gates(app, env, fileMeta) {
|
|
25
|
+
const {
|
|
26
|
+
fileName,
|
|
27
|
+
basename,
|
|
28
|
+
isCompressed
|
|
29
|
+
} = fileMeta;
|
|
30
|
+
const appId = env.appId;
|
|
31
|
+
const envId = env.id;
|
|
32
|
+
const track = _tracker.trackEventWithEnv.bind(null, appId, envId);
|
|
33
|
+
if (!_fs.default.existsSync(fileName)) {
|
|
34
|
+
await track('deploy_app_command_error', {
|
|
35
|
+
error_type: 'invalid-file'
|
|
36
|
+
});
|
|
37
|
+
exit.withError(`Unable to access file ${fileMeta.fileName}`);
|
|
38
|
+
}
|
|
39
|
+
if (!isCompressed) {
|
|
40
|
+
await track('deploy_app_command_error', {
|
|
41
|
+
error_type: 'uncompressed-file'
|
|
42
|
+
});
|
|
43
|
+
exit.withError(`Please compress file ${fileMeta.fileName} before uploading.`);
|
|
44
|
+
}
|
|
45
|
+
try {
|
|
46
|
+
(0, _customDeploy.validateFilename)(basename);
|
|
47
|
+
} catch (error) {
|
|
48
|
+
await track('deploy_app_command_error', {
|
|
49
|
+
error_type: 'invalid-filename'
|
|
50
|
+
});
|
|
51
|
+
exit.withError(error);
|
|
52
|
+
}
|
|
53
|
+
try {
|
|
54
|
+
(0, _customDeploy.validateDeployFileExt)(fileName);
|
|
55
|
+
} catch (error) {
|
|
56
|
+
await track('deploy_app_command_error', {
|
|
57
|
+
error_type: 'invalid-extension'
|
|
58
|
+
});
|
|
59
|
+
exit.withError(error);
|
|
60
|
+
}
|
|
61
|
+
if (!isSupportedApp(app)) {
|
|
62
|
+
await track('deploy_app_command_error', {
|
|
63
|
+
error_type: 'unsupported-app'
|
|
64
|
+
});
|
|
65
|
+
exit.withError('The type of application you specified does not currently support deploys.');
|
|
66
|
+
}
|
|
67
|
+
try {
|
|
68
|
+
await (0, _clientFileUploader.checkFileAccess)(fileName);
|
|
69
|
+
} catch (err) {
|
|
70
|
+
await track('deploy_app_command_error', {
|
|
71
|
+
error_type: 'appfile-unreadable'
|
|
72
|
+
});
|
|
73
|
+
exit.withError(`File '${fileName}' does not exist or is not readable.`);
|
|
74
|
+
}
|
|
75
|
+
if (!(await (0, _clientFileUploader.isFile)(fileName))) {
|
|
76
|
+
await track('deploy_app_command_error', {
|
|
77
|
+
error_type: 'appfile-notfile'
|
|
78
|
+
});
|
|
79
|
+
exit.withError(`Path '${fileName}' is not a file.`);
|
|
80
|
+
}
|
|
81
|
+
const fileSize = await (0, _clientFileUploader.getFileSize)(fileName);
|
|
82
|
+
if (!fileSize) {
|
|
83
|
+
await track('deploy_app_command_error', {
|
|
84
|
+
error_type: 'appfile-empty'
|
|
85
|
+
});
|
|
86
|
+
exit.withError(`File '${fileName}' is empty.`);
|
|
87
|
+
}
|
|
88
|
+
if (fileSize > DEPLOY_MAX_FILE_SIZE) {
|
|
89
|
+
await track('deploy_app_command_error', {
|
|
90
|
+
error_type: 'appfile-toobig',
|
|
91
|
+
file_size: fileSize
|
|
92
|
+
});
|
|
93
|
+
exit.withError(`The deploy file size (${fileSize} bytes) exceeds the limit (${DEPLOY_MAX_FILE_SIZE} bytes).`);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
@@ -107,7 +107,9 @@ const verifyDNSResolution = async slug => {
|
|
|
107
107
|
address = await (0, _promises.lookup)(testDomain, 4);
|
|
108
108
|
debug(`Got DNS response ${address.address}`);
|
|
109
109
|
} catch (error) {
|
|
110
|
-
throw new _userError.default(`DNS resolution for ${testDomain} failed. ${advice}
|
|
110
|
+
throw new _userError.default(`DNS resolution for ${testDomain} failed. ${advice}`, {
|
|
111
|
+
cause: error
|
|
112
|
+
});
|
|
111
113
|
}
|
|
112
114
|
if (address.address !== expectedIP) {
|
|
113
115
|
throw new _userError.default(`DNS resolution for ${testDomain} returned unexpected IP ${address.address}. Expected value is ${expectedIP}. ${advice}`);
|
|
@@ -684,7 +686,7 @@ function getEnvTrackingInfo(slug) {
|
|
|
684
686
|
const value = _devEnvironment.DEV_ENVIRONMENT_COMPONENTS_WITH_WP.includes(key) ? JSON.stringify(envData[key]) : envData[key];
|
|
685
687
|
result[snakeCasedKey] = value;
|
|
686
688
|
}
|
|
687
|
-
result.php = result.php.replace(
|
|
689
|
+
result.php = result.php.replace(/^[^:]+:/, '');
|
|
688
690
|
return result;
|
|
689
691
|
} catch (err) {
|
|
690
692
|
return {
|
|
@@ -7,7 +7,6 @@ exports.mergeConfigurationFileOptions = mergeConfigurationFileOptions;
|
|
|
7
7
|
exports.printConfigurationFile = printConfigurationFile;
|
|
8
8
|
var _chalk = _interopRequireDefault(require("chalk"));
|
|
9
9
|
var _debug = _interopRequireDefault(require("debug"));
|
|
10
|
-
var _fs = require("fs");
|
|
11
10
|
var _jsYaml = _interopRequireWildcard(require("js-yaml"));
|
|
12
11
|
var _promises = require("node:fs/promises");
|
|
13
12
|
var _nodePath = _interopRequireDefault(require("node:path"));
|
|
@@ -20,12 +19,14 @@ const CONFIGURATION_FILE_NAME = exports.CONFIGURATION_FILE_NAME = '.vip-dev-env.
|
|
|
20
19
|
async function getConfigurationFileOptions() {
|
|
21
20
|
const configurationFilePath = _nodePath.default.join(process.cwd(), CONFIGURATION_FILE_NAME);
|
|
22
21
|
let configurationFileContents = '';
|
|
23
|
-
|
|
24
|
-
if (fileExists) {
|
|
25
|
-
debug('Reading configuration file from:', configurationFilePath);
|
|
22
|
+
try {
|
|
26
23
|
configurationFileContents = await (0, _promises.readFile)(configurationFilePath, 'utf8');
|
|
27
|
-
|
|
28
|
-
|
|
24
|
+
debug('Read configuration file from %s', configurationFilePath);
|
|
25
|
+
} catch (err) {
|
|
26
|
+
if (err.code === 'ENOENT') {
|
|
27
|
+
return {};
|
|
28
|
+
}
|
|
29
|
+
throw err;
|
|
29
30
|
}
|
|
30
31
|
let configurationFromFile = {};
|
|
31
32
|
try {
|
|
@@ -29,7 +29,6 @@ var _ejs = _interopRequireDefault(require("ejs"));
|
|
|
29
29
|
var _enquirer = require("enquirer");
|
|
30
30
|
var _nodeFetch = _interopRequireDefault(require("node-fetch"));
|
|
31
31
|
var _nodeFs = _interopRequireDefault(require("node:fs"));
|
|
32
|
-
var _nodeOs = _interopRequireDefault(require("node:os"));
|
|
33
32
|
var _nodePath = _interopRequireDefault(require("node:path"));
|
|
34
33
|
var _semver = _interopRequireDefault(require("semver"));
|
|
35
34
|
var _uuid = require("uuid");
|
|
@@ -53,7 +52,13 @@ const instanceDataFileName = 'instance_data.json';
|
|
|
53
52
|
const uploadPathString = 'uploads';
|
|
54
53
|
const nginxPathString = 'nginx';
|
|
55
54
|
function xdgDataDirectory() {
|
|
56
|
-
|
|
55
|
+
if (_xdgBasedir.default.data) {
|
|
56
|
+
return _xdgBasedir.default.data;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// This should not happen. If it does, this means that the system was unable to find user's home directory.
|
|
60
|
+
// If so, this does not leave us many options as to where to store the data.
|
|
61
|
+
throw new Error('Unable to determine data directory.');
|
|
57
62
|
}
|
|
58
63
|
async function startEnvironment(lando, slug, options) {
|
|
59
64
|
debug('Will start an environment', slug);
|
|
@@ -273,13 +278,17 @@ function readEnvironmentData(slug) {
|
|
|
273
278
|
instanceDataString = _nodeFs.default.readFileSync(instanceDataTargetPath, 'utf8');
|
|
274
279
|
} catch (error) {
|
|
275
280
|
const err = error;
|
|
276
|
-
throw new _userError.default(`There was an error reading file "${instanceDataTargetPath}": ${err.message}
|
|
281
|
+
throw new _userError.default(`There was an error reading file "${instanceDataTargetPath}": ${err.message}.`, {
|
|
282
|
+
cause: error
|
|
283
|
+
});
|
|
277
284
|
}
|
|
278
285
|
try {
|
|
279
286
|
instanceData = JSON.parse(instanceDataString);
|
|
280
287
|
} catch (error) {
|
|
281
288
|
const err = error;
|
|
282
|
-
throw new _userError.default(`There was an error parsing file "${instanceDataTargetPath}": ${err.message}. You may need to recreate the environment
|
|
289
|
+
throw new _userError.default(`There was an error parsing file "${instanceDataTargetPath}": ${err.message}. You may need to recreate the environment.`, {
|
|
290
|
+
cause: error
|
|
291
|
+
});
|
|
283
292
|
}
|
|
284
293
|
|
|
285
294
|
/**
|
|
@@ -334,10 +343,14 @@ async function prepareLandoEnv(instanceData, instancePath) {
|
|
|
334
343
|
await _nodeFs.default.promises.mkdir(nginxFolderPath, {
|
|
335
344
|
recursive: true
|
|
336
345
|
});
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
await _nodeFs.default.promises.copyFile(landoFileTargetPath, landoBackupFileTargetPath);
|
|
346
|
+
try {
|
|
347
|
+
await _nodeFs.default.promises.rename(landoFileTargetPath, landoBackupFileTargetPath);
|
|
340
348
|
console.log(`Backup of ${landoFileName} was created in ${landoBackupFileTargetPath}`);
|
|
349
|
+
} catch (err) {
|
|
350
|
+
// If the file doesn't exist, that's fine. Otherwise, throw the error.
|
|
351
|
+
if ('ENOENT' !== err.code) {
|
|
352
|
+
throw err;
|
|
353
|
+
}
|
|
341
354
|
}
|
|
342
355
|
await Promise.all([_nodeFs.default.promises.writeFile(landoFileTargetPath, landoFile), _nodeFs.default.promises.writeFile(nginxFileTargetPath, nginxFile), _nodeFs.default.promises.writeFile(instanceDataTargetPath, instanceDataFile)]);
|
|
343
356
|
debug(`Lando file created in ${landoFileTargetPath}`);
|
|
@@ -79,7 +79,7 @@ async function getDockerSocket() {
|
|
|
79
79
|
async function getEngineConfig(dockerHost) {
|
|
80
80
|
const opts = {};
|
|
81
81
|
if (dockerHost.startsWith('tcp://')) {
|
|
82
|
-
const split =
|
|
82
|
+
const split = /^(?:tcp:\/\/)([^:]+):(\d+)/g.exec(dockerHost);
|
|
83
83
|
if (split && split.length === 3) {
|
|
84
84
|
opts.host = split[1];
|
|
85
85
|
opts.port = split[2];
|
package/dist/lib/env.js
CHANGED
package/dist/lib/user-error.js
CHANGED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
exports.__esModule = true;
|
|
4
|
+
exports.validateDeployFileExt = validateDeployFileExt;
|
|
5
|
+
exports.validateFilename = validateFilename;
|
|
6
|
+
var _path = _interopRequireDefault(require("path"));
|
|
7
|
+
var exit = _interopRequireWildcard(require("../../lib/cli/exit"));
|
|
8
|
+
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); }
|
|
9
|
+
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 && Object.prototype.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; }
|
|
10
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
11
|
+
/**
|
|
12
|
+
* Check if a file has a valid extension
|
|
13
|
+
*
|
|
14
|
+
* @param {string} filename The file extension
|
|
15
|
+
* @returns {boolean} True if the extension is valid
|
|
16
|
+
*/
|
|
17
|
+
function validateDeployFileExt(filename) {
|
|
18
|
+
let ext = _path.default.extname(filename).toLowerCase();
|
|
19
|
+
if (ext === '.gz' && _path.default.extname(_path.default.basename(filename, ext)) === '.tar') {
|
|
20
|
+
ext = '.tar.gz';
|
|
21
|
+
}
|
|
22
|
+
if (!['.zip', '.tar.gz', '.tgz'].includes(ext)) {
|
|
23
|
+
exit.withError('Invalid file extension. Please provide a .zip, .tar.gz, or a .tgz file.');
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Check if a file has a valid name
|
|
29
|
+
* @param {string} filename The file name
|
|
30
|
+
* @returns {boolean} True if the filename is valid
|
|
31
|
+
*/
|
|
32
|
+
function validateFilename(filename) {
|
|
33
|
+
const re = /^[a-z0-9\-_.]+$/i;
|
|
34
|
+
|
|
35
|
+
// Exits if filename contains anything outside a-z A-Z - _ .
|
|
36
|
+
if (!re.test(filename)) {
|
|
37
|
+
exit.withError('Error: The characters used in the name of a file for custom deploys are limited to [0-9,a-z,A-Z,-,_,.]');
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -36,7 +36,9 @@ async function fileLineValidations(appId, envId, fileName, validations, searchRe
|
|
|
36
36
|
});
|
|
37
37
|
});
|
|
38
38
|
readInterface.on('error', err => {
|
|
39
|
-
throw new Error(`
|
|
39
|
+
throw new Error(`Error validating input file: ${err.toString()}`, {
|
|
40
|
+
cause: err
|
|
41
|
+
});
|
|
40
42
|
});
|
|
41
43
|
|
|
42
44
|
// Block until the processing completes
|
|
@@ -262,7 +262,7 @@ const checks = {
|
|
|
262
262
|
siteHomeUrl: {
|
|
263
263
|
matcher: "'(siteurl|home)',\\s?'(.*?)'",
|
|
264
264
|
matchHandler: (lineNumber, results) => ({
|
|
265
|
-
text: results[1]
|
|
265
|
+
text: results[1] + ' ' + results[2]
|
|
266
266
|
}),
|
|
267
267
|
outputFormatter: infoCheckFormatter,
|
|
268
268
|
results: [],
|
package/docs/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,49 @@
|
|
|
1
1
|
## Changelog
|
|
2
2
|
|
|
3
|
+
### 2.37.0
|
|
4
|
+
|
|
5
|
+
- build(deps-dev): bump the babel group with 2 updates
|
|
6
|
+
- build(deps): bump @automattic/vip-search-replace from 1.1.1 to 1.1.2
|
|
7
|
+
- build(deps): bump Automattic/vip-actions from 0.2.0 to 0.3.0
|
|
8
|
+
- build(deps): bump github/codeql-action from 2 to 3
|
|
9
|
+
- BYOR: Add `vip app deploy`
|
|
10
|
+
- build(deps-dev): bump eslint from 8.55.0 to 8.56.0
|
|
11
|
+
- Dev-env: Remove 8.0 & 7.4 from available PHP versions
|
|
12
|
+
- build(deps): bump open from 9.1.0 to 10.0.0
|
|
13
|
+
- fix(dev-env): use the latest nginx image
|
|
14
|
+
- build(deps-dev): bump dockerode from 4.0.0 to 4.0.1
|
|
15
|
+
- build(deps): bump open from 10.0.0 to 10.0.1
|
|
16
|
+
- build(deps-dev): bump dockerode from 4.0.1 to 4.0.2
|
|
17
|
+
- build(deps): bump open from 10.0.1 to 10.0.2
|
|
18
|
+
- fix(validate-sql): Display matched site-urls
|
|
19
|
+
- build(deps): bump socket.io-client from 4.7.2 to 4.7.3
|
|
20
|
+
- build(deps-dev): bump the babel group with 2 updates
|
|
21
|
+
- build(deps): bump open from 10.0.2 to 10.0.3
|
|
22
|
+
- feat: show detailed error information in debug mode
|
|
23
|
+
- build(deps-dev): bump the babel group with 1 update
|
|
24
|
+
- fix: issues found by SonarCloud
|
|
25
|
+
- build(deps-dev): bump @types/node from 18.19.5 to 18.19.6
|
|
26
|
+
- chore(deps): fix CVE-2023-26159 in follow-redirects
|
|
27
|
+
- build(deps): bump Automattic/vip-actions from 0.3.0 to 0.5.0
|
|
28
|
+
- build(deps): bump @automattic/vip-search-replace from 1.1.2 to 1.1.3
|
|
29
|
+
- fix: Properly propagate quotes
|
|
30
|
+
- fix(--format=json): Do not print header if specified format is json
|
|
31
|
+
- feat(dev-env): add quiet mode for "import sql"
|
|
32
|
+
- build(deps): bump socket.io-client from 4.7.3 to 4.7.4
|
|
33
|
+
- fix: regex vulnerable to super-linear runtime
|
|
34
|
+
- ci: add CodeQL workflow
|
|
35
|
+
- ci: remove outdated CodeQL workflow
|
|
36
|
+
- BYOR: Change manual-deploy to custom-deploy
|
|
37
|
+
- build(deps-dev): bump @types/node from 18.19.6 to 18.19.8
|
|
38
|
+
- build(deps-dev): bump nock from 13.4.0 to 13.5.0
|
|
39
|
+
- fix(dev-env): CWE-367 in `prepareLandoEnv()`
|
|
40
|
+
- fix(dev-env): CWE-367 in `getConfigurationFileOptions()`
|
|
41
|
+
- fix(dev-env): CWE-377, CWE-378 originating from `xdgDataDirectory()`
|
|
42
|
+
- build(deps): bump Automattic/vip-actions from 0.5.0 to 0.6.0
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
**Full Changelog**: https://github.com/Automattic/vip-cli/compare/2.36.3...v2.37.0
|
|
46
|
+
|
|
3
47
|
### 2.36.3
|
|
4
48
|
|
|
5
49
|
- build(deps): bump @json2csv/plainjs from 7.0.3 to 7.0.4
|