@florianpat/lando-core 3.23.7-compose → 3.23.22-test2
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/CHANGELOG.md +101 -1
- package/bin/lando +2 -0
- package/bin/lando.cmd +3 -0
- package/builders/_lando.js +2 -1
- package/components/l337-v4.js +2 -2
- package/config.yml +3 -2
- package/hooks/lando-autostart-engine.js +4 -25
- package/hooks/lando-run-setup.js +58 -0
- package/hooks/lando-setup-build-engine-darwin.js +13 -12
- package/hooks/lando-setup-build-engine-linux.js +14 -4
- package/hooks/lando-setup-build-engine-win32.js +27 -20
- package/hooks/lando-setup-build-engine-wsl.js +210 -0
- package/hooks/lando-setup-check.js +19 -0
- package/hooks/lando-setup-create-ca-wsl.js +34 -0
- package/hooks/lando-setup-create-ca.js +22 -23
- package/hooks/lando-setup-install-ca-darwin.js +5 -1
- package/hooks/lando-setup-install-ca-linux.js +4 -1
- package/hooks/lando-setup-install-ca-win32.js +5 -1
- package/hooks/lando-setup-install-ca-wsl.js +145 -0
- package/hooks/lando-setup-orchestrator.js +4 -4
- package/index.js +18 -12
- package/lib/app.js +2 -2
- package/lib/art.js +20 -8
- package/lib/compose.js +0 -3
- package/lib/daemon.js +79 -76
- package/lib/docker.js +2 -2
- package/lib/engine.js +10 -3
- package/lib/lando.js +2 -2
- package/lib/metrics.js +5 -3
- package/lib/updates.js +12 -2
- package/node_modules/nanoid/.devcontainer.json +23 -0
- package/node_modules/nanoid/README.md +517 -2
- package/node_modules/nanoid/async/index.browser.cjs +37 -2
- package/node_modules/nanoid/async/index.browser.js +37 -2
- package/node_modules/nanoid/async/index.cjs +38 -2
- package/node_modules/nanoid/async/index.js +38 -2
- package/node_modules/nanoid/async/index.native.js +33 -2
- package/node_modules/nanoid/index.browser.cjs +39 -1
- package/node_modules/nanoid/index.browser.js +39 -1
- package/node_modules/nanoid/index.cjs +42 -2
- package/node_modules/nanoid/index.js +42 -2
- package/node_modules/nanoid/non-secure/index.cjs +15 -2
- package/node_modules/nanoid/non-secure/index.js +15 -2
- package/node_modules/nanoid/package.json +1 -1
- package/node_modules/nanoid/url-alphabet/index.cjs +4 -0
- package/node_modules/nanoid/url-alphabet/index.js +4 -0
- package/package.json +7 -7
- package/plugins/networking/app.js +4 -2
- package/plugins/networking/index.js +19 -6
- package/plugins/proxy/builders/_proxy.js +1 -2
- package/release-aliases/3-EDGE +1 -1
- package/release-aliases/3-STABLE +1 -1
- package/renderers/dc2.js +2 -1
- package/scripts/add-to-group.sh +72 -0
- package/scripts/docker-engine-start.sh +15 -1
- package/scripts/install-docker-desktop.ps1 +11 -12
- package/scripts/install-system-ca-win32.ps1 +14 -14
- package/scripts/run-elevated.ps1 +2 -2
- package/scripts/semcompare.sh +142 -0
- package/scripts/wait-for-user.sh +1 -2
- package/tasks/destroy.js +3 -0
- package/tasks/info.js +2 -1
- package/tasks/init.js +35 -30
- package/tasks/rebuild.js +2 -8
- package/tasks/restart.js +2 -8
- package/tasks/setup.js +2 -2
- package/tasks/shellenv.js +2 -2
- package/tasks/start.js +2 -8
- package/tasks/stop.js +3 -0
- package/utils/build-config.js +2 -0
- package/utils/build-tooling-runner.js +2 -1
- package/utils/get-app.js +1 -1
- package/utils/get-bin-paths.js +2 -2
- package/utils/get-compose-x.js +1 -1
- package/utils/get-config-defaults.js +12 -7
- package/utils/get-docker-bin-path.js +6 -2
- package/utils/get-docker-desktop-x.js +21 -0
- package/utils/get-docker-x.js +3 -2
- package/utils/get-shellenv.js +1 -2
- package/utils/get-system-cas.js +25 -6
- package/utils/get-win32-envvar-from-wsl.js +7 -0
- package/utils/is-admin-user.js +9 -8
- package/utils/is-group-member.js +14 -7
- package/utils/is-wsl-interop.js +17 -4
- package/utils/run-elevated.js +9 -0
- package/utils/run-powershell-script.js +31 -5
- package/utils/run-tasks.js +3 -2
- package/utils/setup-metrics.js +10 -1
- package/utils/shutdown-os.js +8 -3
- package/utils/spawn-sync-stringer.js +1 -0
- package/utils/update-shell-profile.js +8 -7
- package/utils/validate-ca.js +31 -0
- package/utils/winpath-2-wslpath.js +6 -0
- package/utils/wslpath-2-winpath.js +6 -0
- package/hooks/lando-dep-check.js +0 -26
- package/lib/checksums.txt +0 -0
package/tasks/setup.js
CHANGED
|
@@ -67,7 +67,7 @@ module.exports = lando => {
|
|
|
67
67
|
// get defaults from the lando config
|
|
68
68
|
const defaults = lando.config.setup;
|
|
69
69
|
// determine label for build engine
|
|
70
|
-
const buildEngine = process.platform === 'linux' ? 'docker-engine' : 'docker-desktop';
|
|
70
|
+
const buildEngine = process.landoPlatform === 'linux' || process.platform === 'linux' ? 'docker-engine' : 'docker-desktop';
|
|
71
71
|
// default options
|
|
72
72
|
const options = {
|
|
73
73
|
'build-engine': {
|
|
@@ -218,7 +218,7 @@ module.exports = lando => {
|
|
|
218
218
|
|
|
219
219
|
// print table
|
|
220
220
|
console.log('');
|
|
221
|
-
ux.table(sortBy(rows, ['
|
|
221
|
+
ux.table(sortBy(rows, ['description', 'weight']), columns);
|
|
222
222
|
console.log('');
|
|
223
223
|
|
|
224
224
|
// things are good!
|
package/tasks/shellenv.js
CHANGED
|
@@ -62,7 +62,7 @@ module.exports = lando => {
|
|
|
62
62
|
console.log();
|
|
63
63
|
console.log(color.bold(binPaths.join(os.EOL)));
|
|
64
64
|
console.log();
|
|
65
|
-
console.log(`
|
|
65
|
+
console.log(`Start a new terminal session to use ${color.bold(`lando`)}`);
|
|
66
66
|
return;
|
|
67
67
|
|
|
68
68
|
// otherwise update the shell profile
|
|
@@ -72,7 +72,7 @@ module.exports = lando => {
|
|
|
72
72
|
console.log();
|
|
73
73
|
console.log(color.bold(shellEnv.map(line => line[0]).join(os.EOL)));
|
|
74
74
|
console.log();
|
|
75
|
-
console.log(`
|
|
75
|
+
console.log(`Start a new terminal session or run ${color.bold(`eval "$(lando shellenv)"`)} to use ${color.bold(`lando`)}`);
|
|
76
76
|
} else {
|
|
77
77
|
console.log(`Looks like ${color.green(options.add)} is already ready to go!`);
|
|
78
78
|
}
|
package/tasks/start.js
CHANGED
|
@@ -16,17 +16,11 @@ module.exports = lando => {
|
|
|
16
16
|
if (app) {
|
|
17
17
|
console.log(lando.cli.makeArt('appStart', {name: app.name, phase: 'pre'}));
|
|
18
18
|
|
|
19
|
-
// run
|
|
20
|
-
|
|
21
|
-
sopts.buildEngine = false;
|
|
22
|
-
sopts.skipCommonPlugins = true;
|
|
23
|
-
sopts.yes = true;
|
|
24
|
-
const setupTasks = await lando.getSetupStatus(sopts);
|
|
19
|
+
// run setup if we need to
|
|
20
|
+
await require('../hooks/lando-run-setup')(lando);
|
|
25
21
|
|
|
26
22
|
// Normal bootup
|
|
27
23
|
try {
|
|
28
|
-
// run a limited setup if needed
|
|
29
|
-
if (setupTasks.length > 0) await lando.setup(sopts);
|
|
30
24
|
// then start up
|
|
31
25
|
await app.start();
|
|
32
26
|
// determine legacy settings
|
package/tasks/stop.js
CHANGED
|
@@ -10,6 +10,9 @@ module.exports = lando => ({
|
|
|
10
10
|
// Stop it if we can!
|
|
11
11
|
if (app) {
|
|
12
12
|
console.log(lando.cli.makeArt('appStop', {name: app.name, phase: 'pre'}));
|
|
13
|
+
// run setup if we need to
|
|
14
|
+
await require('../hooks/lando-run-setup')(lando);
|
|
15
|
+
// stop
|
|
13
16
|
await app.stop();
|
|
14
17
|
console.log(' ');
|
|
15
18
|
console.log(lando.cli.makeArt('appStop', {name: app.name, phase: 'post'}));
|
package/utils/build-config.js
CHANGED
|
@@ -67,6 +67,8 @@ module.exports = options => {
|
|
|
67
67
|
config.engineConfig = getEngineConfig(config);
|
|
68
68
|
// Strip all COMPOSE_ envvars
|
|
69
69
|
config.env = stripEnv('COMPOSE_');
|
|
70
|
+
// Disable docker CLI_HINTS
|
|
71
|
+
config.env.DOCKER_CLI_HINTS = false;
|
|
70
72
|
|
|
71
73
|
// if composeBin is set and orchestratorBin is not set then set one to the other
|
|
72
74
|
if (config.composeBin && !config.orchestratorBin) config.orchestratorBin = config.composeBin;
|
|
@@ -4,7 +4,8 @@ const _ = require('lodash');
|
|
|
4
4
|
const path = require('path');
|
|
5
5
|
|
|
6
6
|
const getContainer = (app, service) => {
|
|
7
|
-
|
|
7
|
+
const separator = _.get(app, '_config.orchestratorSeparator', '_');
|
|
8
|
+
return app?.containers?.[service] ?? `${app.project}${separator}${service}${separator}1`;
|
|
8
9
|
};
|
|
9
10
|
|
|
10
11
|
const getContainerPath = (appRoot, appMount = undefined) => {
|
package/utils/get-app.js
CHANGED
|
@@ -24,7 +24,7 @@ module.exports = (files, userConfRoot) => {
|
|
|
24
24
|
// cast the name to a string...just to make sure.
|
|
25
25
|
config.name = require('../utils/slugify')(config.name);
|
|
26
26
|
// slugify project
|
|
27
|
-
config.project = config.name;
|
|
27
|
+
config.project = require('../utils/docker-composify')(config.name);
|
|
28
28
|
|
|
29
29
|
return _.merge({}, config, {
|
|
30
30
|
configFiles: files,
|
package/utils/get-bin-paths.js
CHANGED
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
const fs = require('fs');
|
|
4
4
|
const path = require('path');
|
|
5
5
|
|
|
6
|
-
module.exports = ({
|
|
7
|
-
return [
|
|
6
|
+
module.exports = ({installPath}) => {
|
|
7
|
+
return [installPath]
|
|
8
8
|
.filter(p => typeof p === 'string' && p !== '' && fs.existsSync(p))
|
|
9
9
|
.map(p => !fs.lstatSync(p).isDirectory() ? path.dirname(p) : p)
|
|
10
10
|
.filter(p => !process.env.PATH.split(path.delimiter).includes(p))
|
package/utils/get-compose-x.js
CHANGED
|
@@ -27,7 +27,7 @@ const getDockerBin = (bin, base, pathFallback = true) => {
|
|
|
27
27
|
}
|
|
28
28
|
};
|
|
29
29
|
|
|
30
|
-
module.exports = ({orchestratorVersion = '2.
|
|
30
|
+
module.exports = ({orchestratorVersion = '2.30.3', userConfRoot = os.tmpdir()} = {}) => {
|
|
31
31
|
const orchestratorBin = `docker-compose-v${orchestratorVersion}`;
|
|
32
32
|
switch (process.platform) {
|
|
33
33
|
case 'darwin':
|
|
@@ -5,21 +5,23 @@ const browsers = ['electron', 'chrome', 'atom-shell'];
|
|
|
5
5
|
const path = require('path');
|
|
6
6
|
const os = require('os');
|
|
7
7
|
|
|
8
|
-
const getBuildEngineVersion = () => {
|
|
9
|
-
switch (
|
|
8
|
+
const getBuildEngineVersion = (platform = process.landoPlatform ?? process.platform) => {
|
|
9
|
+
switch (platform) {
|
|
10
10
|
case 'darwin':
|
|
11
|
-
return '4.
|
|
11
|
+
return '4.36.0';
|
|
12
12
|
case 'linux':
|
|
13
13
|
return '27.3.1';
|
|
14
14
|
case 'win32':
|
|
15
|
-
return '4.
|
|
15
|
+
return '4.36.0';
|
|
16
|
+
case 'wsl':
|
|
17
|
+
return '4.36.0';
|
|
16
18
|
}
|
|
17
19
|
};
|
|
18
20
|
|
|
19
21
|
// Default config
|
|
20
22
|
const defaultConfig = options => ({
|
|
21
|
-
orchestratorSeparator: '
|
|
22
|
-
orchestratorVersion: '2.
|
|
23
|
+
orchestratorSeparator: '_',
|
|
24
|
+
orchestratorVersion: '2.30.3',
|
|
23
25
|
configSources: [],
|
|
24
26
|
coreBase: path.resolve(__dirname, '..'),
|
|
25
27
|
disablePlugins: [],
|
|
@@ -29,13 +31,16 @@ const defaultConfig = options => ({
|
|
|
29
31
|
home: os.homedir(),
|
|
30
32
|
isArmed: _.includes(['arm64', 'aarch64'], process.arch),
|
|
31
33
|
logLevel: 'debug',
|
|
34
|
+
networkLimit: 32,
|
|
32
35
|
node: process.version,
|
|
33
36
|
os: {
|
|
34
37
|
type: os.type(),
|
|
35
38
|
platform: os.platform(),
|
|
39
|
+
landoPlatform: process.landoPlatform ?? process.platform,
|
|
36
40
|
release: os.release(),
|
|
37
41
|
arch: os.arch(),
|
|
38
42
|
isWsl: os.release().toLowerCase().includes('microsoft'),
|
|
43
|
+
isWslInterop: require('../utils/is-wsl-interop')(),
|
|
39
44
|
},
|
|
40
45
|
pluginDirs: [{path: path.join(__dirname, '..'), subdir: 'plugins', namespace: '@lando'}],
|
|
41
46
|
plugins: [],
|
|
@@ -44,7 +49,7 @@ const defaultConfig = options => ({
|
|
|
44
49
|
// this governs both autosetup and the defaults of lando setup
|
|
45
50
|
// @TODO: orchestrator works a bit differently because it predates lando.setup() we set it elsewhere
|
|
46
51
|
setup: {
|
|
47
|
-
buildEngine: getBuildEngineVersion(),
|
|
52
|
+
buildEngine: getBuildEngineVersion(process.landoPlatform ?? process.platform),
|
|
48
53
|
buildEngineAcceptLicense: !require('is-interactive')(),
|
|
49
54
|
commonPlugins: {
|
|
50
55
|
'@lando/acquia': 'latest',
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
const fs = require('fs');
|
|
4
4
|
const path = require('path');
|
|
5
5
|
|
|
6
|
-
module.exports = () => {
|
|
7
|
-
switch (
|
|
6
|
+
module.exports = (platform = process.landoPlatform ?? process.platform) => {
|
|
7
|
+
switch (platform) {
|
|
8
8
|
case 'darwin':
|
|
9
9
|
return '/Applications/Docker.app/Contents/Resources/bin';
|
|
10
10
|
case 'linux':
|
|
@@ -19,5 +19,9 @@ module.exports = () => {
|
|
|
19
19
|
} else {
|
|
20
20
|
return path.win32.join(programFiles + '\\Docker\\Docker\\resources\\bin');
|
|
21
21
|
}
|
|
22
|
+
case 'wsl':
|
|
23
|
+
return '/mnt/wsl/docker-desktop/cli-tools/usr/bin';
|
|
24
|
+
default:
|
|
25
|
+
return '/usr/bin';
|
|
22
26
|
}
|
|
23
27
|
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const getWinEnvar = require('../utils/get-win32-envvar-from-wsl');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const wslpath = require('./winpath-2-wslpath');
|
|
6
|
+
|
|
7
|
+
module.exports = (platform = process.landoPlatform ?? process.platform) => {
|
|
8
|
+
switch (platform) {
|
|
9
|
+
case 'darwin':
|
|
10
|
+
return '/Applications/Docker.app';
|
|
11
|
+
case 'win32': {
|
|
12
|
+
const programFiles = process.env.ProgramW6432 ?? process.env.ProgramFiles;
|
|
13
|
+
return path.win32.join(`${programFiles}\\Docker\\Docker\\Docker Desktop.exe`);
|
|
14
|
+
}
|
|
15
|
+
case 'wsl': {
|
|
16
|
+
const programFiles = getWinEnvar('ProgramW6432') ?? getWinEnvar('ProgramFiles');
|
|
17
|
+
const winpath = path.win32.join(`${programFiles}\\Docker\\Docker\\Docker Desktop.exe`);
|
|
18
|
+
return wslpath(winpath);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
};
|
package/utils/get-docker-x.js
CHANGED
|
@@ -19,14 +19,15 @@ const getDockerBin = (bin, base, pathFallback = true) => {
|
|
|
19
19
|
if (!fs.existsSync(binPath)) return false;
|
|
20
20
|
|
|
21
21
|
// Otherwise return a normalized binpath
|
|
22
|
-
switch (process.platform) {
|
|
22
|
+
switch (process.landoPlatform ?? process.platform) {
|
|
23
23
|
case 'darwin': return path.posix.normalize(binPath);
|
|
24
24
|
case 'linux': return path.posix.normalize(binPath);
|
|
25
25
|
case 'win32': return path.win32.normalize(binPath);
|
|
26
|
+
case 'wsl': return path.posix.normalize(binPath);
|
|
26
27
|
}
|
|
27
28
|
};
|
|
28
29
|
|
|
29
30
|
module.exports = () => {
|
|
30
|
-
const base = (process.platform === 'linux') ? '/usr/bin' : require('./get-docker-bin-path')();
|
|
31
|
+
const base = (process.landoPlatform === 'linux' || process.platform === 'linux') ? '/usr/bin' : require('./get-docker-bin-path')();
|
|
31
32
|
return getDockerBin('docker', base);
|
|
32
33
|
};
|
package/utils/get-shellenv.js
CHANGED
|
@@ -29,8 +29,7 @@ module.exports = (paths = [], shell = require('./get-user-shell')()) => {
|
|
|
29
29
|
|
|
30
30
|
default:
|
|
31
31
|
return [
|
|
32
|
-
[
|
|
33
|
-
[`export PATH="${paths}\${PATH+:$PATH}"; #landopath`, '#landopath'],
|
|
32
|
+
[`export PATH="${paths}:$PATH"; #landopath`, '#landopath'],
|
|
34
33
|
];
|
|
35
34
|
}
|
|
36
35
|
};
|
package/utils/get-system-cas.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
const os = require('os');
|
|
4
|
+
|
|
5
|
+
/*
|
|
4
6
|
* Retrieves system Certificate Authority (CA) certificates based on the current platform.
|
|
5
7
|
*
|
|
6
8
|
* This function handles different platforms (macOS, Linux, Windows) and returns
|
|
@@ -15,17 +17,21 @@
|
|
|
15
17
|
* @throws {Error} May throw errors during certificate processing, which are logged
|
|
16
18
|
* to the console but do not interrupt the function's execution.
|
|
17
19
|
*/
|
|
18
|
-
module.exports = (
|
|
20
|
+
module.exports = async ({
|
|
21
|
+
format = 'fingerprint',
|
|
22
|
+
platform = process.landoPlatform ?? process.platform,
|
|
23
|
+
}= {}) => {
|
|
19
24
|
const fingerprints = [];
|
|
20
25
|
|
|
21
|
-
switch (
|
|
26
|
+
switch (platform) {
|
|
22
27
|
case 'darwin':
|
|
23
28
|
// For macOS, we use the 'mac-ca' library which handles the formatting
|
|
24
29
|
return require('mac-ca').get({format});
|
|
30
|
+
|
|
25
31
|
case 'linux':
|
|
26
32
|
// For Linux, we use the 'system-ca' library to get system certificates
|
|
27
|
-
const {
|
|
28
|
-
for (const cert of
|
|
33
|
+
const {systemCertsAsync} = require('system-ca');
|
|
34
|
+
for (const cert of await systemCertsAsync()) {
|
|
29
35
|
try {
|
|
30
36
|
fingerprints.push(require('./get-fingerprint')(cert));
|
|
31
37
|
} catch {
|
|
@@ -48,8 +54,21 @@ module.exports = (format = 'fingerprint') => {
|
|
|
48
54
|
}
|
|
49
55
|
}
|
|
50
56
|
|
|
57
|
+
return fingerprints;
|
|
58
|
+
case 'wsl':
|
|
59
|
+
const {stdout} = await require('./run-command')(
|
|
60
|
+
'powershell.exe',
|
|
61
|
+
['-Command', 'Get-ChildItem -Path Cert:\\CurrentUser\\Root | Select-Object -ExpandProperty Thumbprint'],
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
fingerprints.push(...stdout
|
|
65
|
+
.split(os.EOL)
|
|
66
|
+
.map(fingerprint => fingerprint.trim())
|
|
67
|
+
.map(fingerprint => fingerprint.toLowerCase())
|
|
68
|
+
.filter(fingerprint => fingerprint && fingerprint !== ''));
|
|
69
|
+
|
|
51
70
|
return fingerprints;
|
|
52
71
|
default:
|
|
53
|
-
throw new Error(`Unsupported platform: ${
|
|
72
|
+
throw new Error(`Unsupported platform: ${platform}`);
|
|
54
73
|
}
|
|
55
74
|
};
|
package/utils/is-admin-user.js
CHANGED
|
@@ -2,21 +2,22 @@
|
|
|
2
2
|
|
|
3
3
|
const os = require('os');
|
|
4
4
|
|
|
5
|
-
module.exports = user => {
|
|
5
|
+
module.exports = (user, {platform = process.platform} = {}) => {
|
|
6
6
|
// set user to person running this process if its not set
|
|
7
7
|
if (!user) user = os.userInfo().username;
|
|
8
8
|
|
|
9
9
|
// differetn strokes, different folks
|
|
10
|
-
switch (
|
|
10
|
+
switch (platform) {
|
|
11
11
|
case 'darwin':
|
|
12
|
-
return require('./is-group-member')('admin', user);
|
|
12
|
+
return require('./is-group-member')('admin', user, platform);
|
|
13
13
|
case 'linux':
|
|
14
|
-
return require('./is-group-member')('sudo', user)
|
|
15
|
-
|| require('./is-group-member')('admin', user)
|
|
16
|
-
|| require('./is-group-member')('wheel', user)
|
|
17
|
-
|| require('./is-group-member')('adm', user);
|
|
14
|
+
return require('./is-group-member')('sudo', user, platform)
|
|
15
|
+
|| require('./is-group-member')('admin', user, platform)
|
|
16
|
+
|| require('./is-group-member')('wheel', user, platform)
|
|
17
|
+
|| require('./is-group-member')('adm', user, platform);
|
|
18
18
|
case 'win32':
|
|
19
|
-
return require('./is-group-member')('
|
|
19
|
+
return require('./is-group-member')('S-1-5-32-544', user, platform)
|
|
20
|
+
|| require('./is-group-member')('administrators', user, platform);
|
|
20
21
|
default:
|
|
21
22
|
return false;
|
|
22
23
|
}
|
package/utils/is-group-member.js
CHANGED
|
@@ -4,35 +4,42 @@ const os = require('os');
|
|
|
4
4
|
|
|
5
5
|
const posixCmd = user => (['groups', [user]]);
|
|
6
6
|
const win32Cmd = user => ([
|
|
7
|
-
'powershell',
|
|
7
|
+
'powershell.exe',
|
|
8
8
|
[
|
|
9
9
|
'-Command',
|
|
10
10
|
`Get-LocalGroup | Where-Object { ($_ | Get-LocalGroupMember | Where-Object { $_.Name -like "*\\${user}" }).Count -gt 0 } | Select-Object -Property Name`, // eslint-disable-line max-len
|
|
11
11
|
],
|
|
12
12
|
]);
|
|
13
13
|
|
|
14
|
-
module.exports = (group, user) => {
|
|
14
|
+
module.exports = (group, user, platform = process.platform) => {
|
|
15
15
|
// @TODO: throw error if no group specified?
|
|
16
16
|
// set user to person running this process if its not set
|
|
17
17
|
if (!user) user = os.userInfo().username;
|
|
18
18
|
|
|
19
19
|
// get the result of the membership command
|
|
20
|
-
const cmd =
|
|
20
|
+
const cmd = platform === 'win32' ? win32Cmd(user) : posixCmd(user);
|
|
21
21
|
const {status, stdout, stderr} = require('./spawn-sync-stringer')(...cmd);
|
|
22
22
|
|
|
23
23
|
// if we failed for some reason
|
|
24
24
|
if (status !== 0) throw new Error(`Could not determine group situation: ${stderr}`);
|
|
25
25
|
|
|
26
26
|
// mac and linux
|
|
27
|
-
if (
|
|
27
|
+
if (platform === 'darwin' || platform === 'linux') {
|
|
28
28
|
const groups = stdout.split(' ').map(group => group.trim());
|
|
29
29
|
return groups.includes(group);
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
// if windows we have a long command to check
|
|
33
|
-
if (
|
|
34
|
-
const
|
|
35
|
-
|
|
33
|
+
if (platform === 'win32') {
|
|
34
|
+
const ids = stdout
|
|
35
|
+
.split(os.EOL)
|
|
36
|
+
.map(group => group.trim())
|
|
37
|
+
.filter(group => group !== 'Name' && group !== '----')
|
|
38
|
+
.map(group => group.toUpperCase());
|
|
39
|
+
|
|
40
|
+
const matches = ids.filter(id => id === group.toUpperCase() || id.endsWith(group.toUpperCase()));
|
|
41
|
+
|
|
42
|
+
return matches.length > 0;
|
|
36
43
|
}
|
|
37
44
|
|
|
38
45
|
// otherwise false?
|
package/utils/is-wsl-interop.js
CHANGED
|
@@ -3,9 +3,22 @@
|
|
|
3
3
|
const fs = require('fs');
|
|
4
4
|
const os = require('os');
|
|
5
5
|
|
|
6
|
+
const WINBIN_REGEX = /\/mnt\/.\/WINDOWS\/System32$/i;
|
|
7
|
+
|
|
6
8
|
// Checks to see if Docker is installed via WSL/Windows interop.
|
|
7
|
-
module.exports =
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
module.exports = () => {
|
|
10
|
+
// return anything that is not wsl as false
|
|
11
|
+
if (!os.release().toLowerCase().includes('microsoft')) return false;
|
|
12
|
+
|
|
13
|
+
// if we dont have have WSL_INTEROP then
|
|
14
|
+
if (!process.env.WSL_INTEROP) return false;
|
|
15
|
+
|
|
16
|
+
// attempt to find there the winbin is at
|
|
17
|
+
const winbin = process.env.PATH.split(':').filter(path => WINBIN_REGEX.test(path));
|
|
18
|
+
|
|
19
|
+
// if we cant find anything then false
|
|
20
|
+
if (winbin.length === 0) return false;
|
|
21
|
+
|
|
22
|
+
// otherwise return whether our first match exists
|
|
23
|
+
return fs.existsSync(winbin[0]);
|
|
11
24
|
};
|
package/utils/run-elevated.js
CHANGED
|
@@ -11,6 +11,7 @@ const {spawn} = require('child_process');
|
|
|
11
11
|
|
|
12
12
|
// get the bosmang
|
|
13
13
|
const defaults = {
|
|
14
|
+
encode: undefined,
|
|
14
15
|
env: process.env,
|
|
15
16
|
debug: require('debug')('@lando/run-elevated'),
|
|
16
17
|
ignoreReturnCode: false,
|
|
@@ -95,9 +96,17 @@ module.exports = (command, options, stdout = '', stderr = '') => {
|
|
|
95
96
|
debug('elevated command %o done with code %o', command, code);
|
|
96
97
|
// with run-elevate we want to clean up stderr a bit if we can eg remove the powershell shit
|
|
97
98
|
if (options.method === 'run-elevated') {
|
|
99
|
+
const raw = stderr;
|
|
100
|
+
|
|
98
101
|
stderr = stderr.split('. At line')[0];
|
|
99
102
|
stderr = stderr.split(`${os.EOL}At `)[0];
|
|
100
103
|
|
|
104
|
+
// add nse if we have one
|
|
105
|
+
if (raw.split('NativeCommandError')[1]) {
|
|
106
|
+
const nse = raw.split('NativeCommandError')[1];
|
|
107
|
+
stderr = `${stderr}. ${nse.trim()}`;
|
|
108
|
+
}
|
|
109
|
+
|
|
101
110
|
// simplify the UAC cancel error
|
|
102
111
|
if (stderr.includes('The operation was canceled by the user.')) {
|
|
103
112
|
stderr = 'The operation was canceled by the user.';
|
|
@@ -2,24 +2,50 @@
|
|
|
2
2
|
|
|
3
3
|
// Modules
|
|
4
4
|
const merge = require('lodash/merge');
|
|
5
|
+
const read = require('./read-file');
|
|
6
|
+
const winpath = require('./wslpath-2-winpath');
|
|
5
7
|
|
|
6
|
-
const {spawn} = require('child_process');
|
|
8
|
+
const {spawn, spawnSync} = require('child_process');
|
|
9
|
+
|
|
10
|
+
const parseArgs = args => args.map(arg => arg.startsWith('-') ? arg : `"${arg}"`).join(' ');
|
|
7
11
|
|
|
8
12
|
// get the bosmang
|
|
9
13
|
const defaults = {
|
|
14
|
+
encode: undefined,
|
|
15
|
+
env: process.env,
|
|
10
16
|
debug: require('debug')('@lando/run-powershell-script'),
|
|
11
17
|
ignoreReturnCode: false,
|
|
18
|
+
toWSLPath: false,
|
|
12
19
|
};
|
|
13
20
|
|
|
14
|
-
module.exports = (script, args = [], options = {}, stdout = '', stderr = '') => {
|
|
15
|
-
// @TODO: error handling?
|
|
21
|
+
module.exports = (script, args = [], options = {}, stdout = '', stderr = '', cargs = []) => {
|
|
16
22
|
// merge our options over the defaults
|
|
17
23
|
options = merge({}, defaults, options);
|
|
24
|
+
|
|
25
|
+
// if encode is not explicitly set then we need to pick a good value
|
|
26
|
+
if (options.encode === undefined) {
|
|
27
|
+
const bargs = ['Set-ExecutionPolicy', '-Scope', 'Process', '-ExecutionPolicy', 'Bypass'];
|
|
28
|
+
const {status} = spawnSync('powershell.exe', bargs, options);
|
|
29
|
+
options.encode = status !== 0;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// if encode is true we need to do a bunch of other stuff
|
|
33
|
+
if (options.encode === true) {
|
|
34
|
+
const command = `& {${read(script)}} ${parseArgs(args)}`;
|
|
35
|
+
cargs.push('-EncodedCommand', Buffer.from(command, 'utf16le').toString('base64'));
|
|
36
|
+
|
|
37
|
+
// otherwise its pretty easy but note that we may path translate to a winpath if toWSLPath is on
|
|
38
|
+
} else {
|
|
39
|
+
if (options.toWSLPath) script = winpath(script);
|
|
40
|
+
cargs.push('-ExecutionPolicy', 'Bypass', '-File', script, ...args);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// pull out debug
|
|
18
44
|
const {debug} = options;
|
|
19
45
|
|
|
20
46
|
// birth
|
|
21
|
-
debug('running powershell script %o %o', script, args);
|
|
22
|
-
const child = spawn('powershell', ['-
|
|
47
|
+
debug('running powershell script %o %o %o', script, args);
|
|
48
|
+
const child = spawn('powershell.exe', ['-NoProfile'].concat(cargs), options);
|
|
23
49
|
|
|
24
50
|
return require('./merge-promise')(child, async () => {
|
|
25
51
|
return new Promise((resolve, reject) => {
|
package/utils/run-tasks.js
CHANGED
|
@@ -35,8 +35,9 @@ module.exports = async (tasks, {
|
|
|
35
35
|
fallbackRendererOptions = rendererOptions;
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
//
|
|
39
|
-
if (process?.env?.TERM === 'dumb') renderer = '
|
|
38
|
+
// some sitautions just need the bare minimum
|
|
39
|
+
if (process?.env?.TERM === 'dumb') renderer = 'simple';
|
|
40
|
+
if (process?.env?.CI && !require('is-interactive')()) renderer = 'simple';
|
|
40
41
|
|
|
41
42
|
const defaults = {
|
|
42
43
|
ctx: {data: {}, errors: [], results: [], skipped: 0, ran: 0, total: 0},
|
package/utils/setup-metrics.js
CHANGED
|
@@ -18,10 +18,19 @@ const getMetricsContext = () => {
|
|
|
18
18
|
module.exports = (log, config) => {
|
|
19
19
|
const Metrics = require('./../lib/metrics');
|
|
20
20
|
const command = _.get(config, 'command._', 'unknown');
|
|
21
|
+
|
|
22
|
+
// group by endpoints and resolve multiples
|
|
23
|
+
const endpoints = _(_.groupBy(config.stats, 'url'))
|
|
24
|
+
.map((data, url) => ({
|
|
25
|
+
url,
|
|
26
|
+
report: data.map(data => data.report).every(report => report === true),
|
|
27
|
+
}))
|
|
28
|
+
.value();
|
|
29
|
+
|
|
21
30
|
return new Metrics({
|
|
22
31
|
log,
|
|
23
32
|
id: config.id,
|
|
24
|
-
endpoints
|
|
33
|
+
endpoints,
|
|
25
34
|
data: {
|
|
26
35
|
command: `lando ${command}`,
|
|
27
36
|
context: getMetricsContext(),
|
package/utils/shutdown-os.js
CHANGED
|
@@ -6,11 +6,12 @@ module.exports = ({
|
|
|
6
6
|
message = 'Lando wants to restart your computer',
|
|
7
7
|
password = undefined,
|
|
8
8
|
type = 'restart',
|
|
9
|
-
wait = process.platform === 'win32' ? 5 : 'now',
|
|
9
|
+
wait = process.landoPlatform === 'win32' || process.platform === 'win32' ? 5 : 'now',
|
|
10
|
+
platform = process.landoPlatform ?? process.platform,
|
|
10
11
|
} = {}) => {
|
|
11
12
|
debug('shutdown with %o %o', type, {message, wait});
|
|
12
13
|
|
|
13
|
-
switch (
|
|
14
|
+
switch (platform) {
|
|
14
15
|
case 'darwin':
|
|
15
16
|
args.push('shutdown');
|
|
16
17
|
// handle the restart type
|
|
@@ -48,6 +49,10 @@ module.exports = ({
|
|
|
48
49
|
args.push('/c');
|
|
49
50
|
args.push(message);
|
|
50
51
|
|
|
51
|
-
return require('./run-command')('shutdown', args, {debug});
|
|
52
|
+
return require('./run-command')('shutdown.exe', args, {debug});
|
|
53
|
+
case 'wsl':
|
|
54
|
+
args.push('-Command');
|
|
55
|
+
args.push(`wsl --terminate ${process.env.WSL_DISTRO_NAME}`);
|
|
56
|
+
return require('./run-command')('powershell.exe', args, {debug});
|
|
52
57
|
}
|
|
53
58
|
};
|
|
@@ -6,6 +6,12 @@ const os = require('os');
|
|
|
6
6
|
const read = require('./read-file');
|
|
7
7
|
const write = require('./write-file');
|
|
8
8
|
|
|
9
|
+
const trim = (data = []) => {
|
|
10
|
+
while (data.length > 0 && data[data.length - 1] === '') data.pop();
|
|
11
|
+
data.push('');
|
|
12
|
+
return data;
|
|
13
|
+
};
|
|
14
|
+
|
|
9
15
|
module.exports = (file, updates = []) => {
|
|
10
16
|
// create empty file if it doesnt exist first
|
|
11
17
|
if (!fs.existsSync(file)) {
|
|
@@ -17,9 +23,7 @@ module.exports = (file, updates = []) => {
|
|
|
17
23
|
// get the content
|
|
18
24
|
const content = read(file);
|
|
19
25
|
// split into lines
|
|
20
|
-
const lines = content.split('\n');
|
|
21
|
-
// if we end up with second to last line that is empty then pop
|
|
22
|
-
if (lines[lines.length - 2].trim() === '') lines.pop();
|
|
26
|
+
const lines = trim(content.split('\n'));
|
|
23
27
|
|
|
24
28
|
// loops through the updates and add/update as needed
|
|
25
29
|
for (const [update, search] of updates) {
|
|
@@ -31,11 +35,8 @@ module.exports = (file, updates = []) => {
|
|
|
31
35
|
}
|
|
32
36
|
}
|
|
33
37
|
|
|
34
|
-
// if the last element doesnt contain a newline
|
|
35
|
-
if (!lines[lines.length - 1].includes(os.EOL)) lines.push(os.EOL);
|
|
36
|
-
|
|
37
38
|
// Write the modified content back to the file
|
|
38
|
-
write(file, lines.join(os.EOL));
|
|
39
|
+
write(file, `${trim(lines).join(os.EOL)}${os.EOL}`);
|
|
39
40
|
|
|
40
41
|
// handle errors
|
|
41
42
|
} catch (error) {
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const forge = require('node-forge');
|
|
4
|
+
const read = require('./read-file');
|
|
5
|
+
|
|
6
|
+
module.exports = (cert, key, {
|
|
7
|
+
debug = require('debug')('@lando/validate-script'),
|
|
8
|
+
} = {}) => {
|
|
9
|
+
try {
|
|
10
|
+
cert = forge.pki.certificateFromPem(read(cert));
|
|
11
|
+
key = forge.pki.privateKeyFromPem(read(key));
|
|
12
|
+
|
|
13
|
+
// verify the signature using the public key in the CA certificate
|
|
14
|
+
const md = forge.md.sha256.create();
|
|
15
|
+
md.update('taanab', 'utf8');
|
|
16
|
+
const signature = key.sign(md);
|
|
17
|
+
|
|
18
|
+
// if they dont match then throw
|
|
19
|
+
if (!cert.publicKey.verify(md.digest().bytes(), signature)) {
|
|
20
|
+
debug('CA and its private key do not match');
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// otherwise we are good
|
|
25
|
+
return true;
|
|
26
|
+
} catch (error) {
|
|
27
|
+
debug('something is wrong with the CA %o', error.message);
|
|
28
|
+
debug('%o', error);
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
};
|