@florianpat/lando-core 3.23.3-compose → 3.23.22-test1

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.
Files changed (107) hide show
  1. package/CHANGELOG.md +117 -1
  2. package/_redirects +1 -0
  3. package/bin/lando +2 -0
  4. package/bin/lando.cmd +3 -0
  5. package/builders/_lando.js +2 -1
  6. package/checksums.txt +0 -0
  7. package/components/l337-v4.js +2 -2
  8. package/components/plugin.js +1 -1
  9. package/config.yml +3 -2
  10. package/hooks/app-run-events.js +22 -0
  11. package/hooks/lando-autostart-engine.js +4 -25
  12. package/hooks/lando-run-setup.js +58 -0
  13. package/hooks/lando-setup-build-engine-darwin.js +13 -12
  14. package/hooks/lando-setup-build-engine-linux.js +14 -4
  15. package/hooks/lando-setup-build-engine-win32.js +27 -20
  16. package/hooks/lando-setup-build-engine-wsl.js +210 -0
  17. package/hooks/lando-setup-check.js +19 -0
  18. package/hooks/lando-setup-create-ca-wsl.js +34 -0
  19. package/hooks/lando-setup-create-ca.js +22 -23
  20. package/hooks/lando-setup-install-ca-darwin.js +5 -1
  21. package/hooks/lando-setup-install-ca-linux.js +4 -1
  22. package/hooks/lando-setup-install-ca-win32.js +5 -1
  23. package/hooks/lando-setup-install-ca-wsl.js +145 -0
  24. package/hooks/lando-setup-orchestrator.js +4 -4
  25. package/index.js +18 -12
  26. package/lib/app.js +2 -2
  27. package/lib/art.js +20 -8
  28. package/lib/compose.js +0 -3
  29. package/lib/daemon.js +79 -76
  30. package/lib/docker.js +2 -2
  31. package/lib/engine.js +10 -3
  32. package/lib/lando.js +2 -2
  33. package/lib/metrics.js +5 -3
  34. package/lib/router.js +1 -1
  35. package/lib/updates.js +18 -3
  36. package/netlify.toml +1 -6
  37. package/node_modules/cross-spawn/README.md +3 -10
  38. package/node_modules/cross-spawn/lib/enoent.js +1 -1
  39. package/node_modules/cross-spawn/lib/util/escape.js +4 -2
  40. package/node_modules/cross-spawn/package.json +1 -1
  41. package/node_modules/nanoid/.devcontainer.json +23 -0
  42. package/node_modules/nanoid/README.md +517 -2
  43. package/node_modules/nanoid/async/index.browser.cjs +37 -2
  44. package/node_modules/nanoid/async/index.browser.js +37 -2
  45. package/node_modules/nanoid/async/index.cjs +38 -2
  46. package/node_modules/nanoid/async/index.js +38 -2
  47. package/node_modules/nanoid/async/index.native.js +33 -2
  48. package/node_modules/nanoid/index.browser.cjs +39 -1
  49. package/node_modules/nanoid/index.browser.js +39 -1
  50. package/node_modules/nanoid/index.cjs +42 -2
  51. package/node_modules/nanoid/index.js +42 -2
  52. package/node_modules/nanoid/non-secure/index.cjs +15 -2
  53. package/node_modules/nanoid/non-secure/index.js +15 -2
  54. package/node_modules/nanoid/package.json +1 -1
  55. package/node_modules/nanoid/url-alphabet/index.cjs +4 -0
  56. package/node_modules/nanoid/url-alphabet/index.js +4 -0
  57. package/package.json +9 -8
  58. package/plugins/networking/app.js +4 -2
  59. package/plugins/networking/index.js +19 -6
  60. package/plugins/proxy/builders/_proxy.js +1 -2
  61. package/release-aliases/3-EDGE +1 -1
  62. package/release-aliases/3-STABLE +1 -1
  63. package/renderers/dc2.js +2 -1
  64. package/scripts/add-to-group.sh +72 -0
  65. package/scripts/docker-engine-start.sh +15 -1
  66. package/scripts/generate-checksums.sh +2 -2
  67. package/scripts/install-docker-desktop.ps1 +11 -12
  68. package/scripts/install-system-ca-win32.ps1 +14 -14
  69. package/scripts/lando-entrypoint.sh +4 -0
  70. package/scripts/run-elevated.ps1 +2 -2
  71. package/scripts/semcompare.sh +142 -0
  72. package/scripts/wait-for-user.sh +1 -2
  73. package/tasks/destroy.js +3 -0
  74. package/tasks/info.js +2 -1
  75. package/tasks/init.js +35 -30
  76. package/tasks/rebuild.js +2 -8
  77. package/tasks/restart.js +2 -8
  78. package/tasks/setup.js +2 -2
  79. package/tasks/shellenv.js +2 -2
  80. package/tasks/start.js +2 -8
  81. package/tasks/stop.js +3 -0
  82. package/utils/build-config.js +2 -0
  83. package/utils/build-tooling-runner.js +2 -1
  84. package/utils/get-app.js +1 -1
  85. package/utils/get-bin-paths.js +2 -2
  86. package/utils/get-compose-x.js +1 -1
  87. package/utils/get-config-defaults.js +12 -7
  88. package/utils/get-docker-bin-path.js +6 -2
  89. package/utils/get-docker-desktop-x.js +21 -0
  90. package/utils/get-docker-x.js +3 -2
  91. package/utils/get-shellenv.js +1 -2
  92. package/utils/get-system-cas.js +25 -6
  93. package/utils/get-win32-envvar-from-wsl.js +7 -0
  94. package/utils/is-admin-user.js +9 -8
  95. package/utils/is-group-member.js +14 -7
  96. package/utils/is-wsl-interop.js +17 -4
  97. package/utils/run-elevated.js +9 -0
  98. package/utils/run-powershell-script.js +31 -5
  99. package/utils/run-tasks.js +3 -2
  100. package/utils/setup-metrics.js +10 -1
  101. package/utils/shutdown-os.js +8 -3
  102. package/utils/spawn-sync-stringer.js +1 -0
  103. package/utils/update-shell-profile.js +8 -7
  104. package/utils/validate-ca.js +31 -0
  105. package/utils/winpath-2-wslpath.js +6 -0
  106. package/utils/wslpath-2-winpath.js +6 -0
  107. package/hooks/lando-dep-check.js +0 -26
package/tasks/init.js CHANGED
@@ -44,7 +44,7 @@ const runBuild = (lando, options = {}, steps = []) => lando.Promise.each(steps,
44
44
  step,
45
45
  )),
46
46
  );
47
- };
47
+ }
48
48
  });
49
49
 
50
50
  module.exports = lando => {
@@ -80,7 +80,7 @@ module.exports = lando => {
80
80
  [--yes]
81
81
  [--other-plugin-provided-options...]`,
82
82
  options: _.merge(getInitBaseOpts(recipes, sources), configOpts, getInitOveridesOpts(inits, recipes, sources)),
83
- run: options => {
83
+ run: async options => {
84
84
  // Parse options abd and configs
85
85
  options = parseInitOptions(options);
86
86
  // Get our recipe and source configs
@@ -90,44 +90,49 @@ module.exports = lando => {
90
90
  const buildSteps = (_.has(sourceConfig, 'build')) ? sourceConfig.build(options, lando) : [];
91
91
  const configStep = (_.has(recipeConfig, 'build')) ? recipeConfig.build : () => {};
92
92
 
93
+ // run setup if we need to
94
+ await require('../hooks/lando-run-setup')(lando);
95
+
93
96
  // Pre init event and run build steps
94
97
  // @NOTE: source build steps are designed to grab code from somewhere
95
- return lando.events.emit('pre-init', options, buildSteps).then(() => runBuild(lando, options, buildSteps))
98
+ await lando.events.emit('pre-init', options, buildSteps);
99
+
100
+ // run build
101
+ await runBuild(lando, options, buildSteps);
102
+
96
103
  // Run any config steps
97
104
  // @NOTE: config steps are designed to augmnet the landofile with additional metadata
98
- .then(() => configStep(options, lando))
105
+ const config = await configStep(options, lando);
99
106
 
100
107
  // Compile and dump the yaml
101
- .then((config = {}) => {
102
- // if config is false then it means we want to skip landofile mutation
103
- if (config !== false) {
104
- // Where are we going?
105
- const dest = path.join(options.destination, '.lando.yml');
106
- const landoFile = getYaml(dest, options, lando);
107
-
108
- // Get a lower level config if needed, merge in current recipe config
109
- if (options.full) {
110
- const Recipe = lando.factory.get(options.recipe);
111
- const recipeConfig = _.merge({}, landoFile, {app: landoFile.name, _app: {_config: lando.config}});
112
- _.merge(landoFile, new Recipe(landoFile.name, recipeConfig).config);
113
- }
114
-
115
- // Merge in any additional configuration options specified
116
- _.forEach(options.option, option => {
117
- const key = _.first(option.split('='));
118
- _.set(landoFile, `config.${key}`, _.last(option.split('=')));
119
- });
120
-
121
- // Merge and dump the config file
122
- lando.yaml.dump(dest, _.merge(landoFile, config));
108
+ // if config is false then it means we want to skip landofile mutation
109
+ if (config !== false) {
110
+ // Where are we going?
111
+ const dest = path.join(options.destination, '.lando.yml');
112
+ const landoFile = getYaml(dest, options, lando);
113
+
114
+ // Get a lower level config if needed, merge in current recipe config
115
+ if (options.full) {
116
+ const Recipe = lando.factory.get(options.recipe);
117
+ const recipeConfig = _.merge({}, landoFile, {app: landoFile.name, _app: {_config: lando.config}});
118
+ _.merge(landoFile, new Recipe(landoFile.name, recipeConfig).config);
123
119
  }
124
120
 
125
- // Show it
126
- showInit(lando, options);
127
- })
121
+ // Merge in any additional configuration options specified
122
+ _.forEach(options.option, option => {
123
+ const key = _.first(option.split('='));
124
+ _.set(landoFile, `config.${key}`, _.last(option.split('=')));
125
+ });
126
+
127
+ // Merge and dump the config file
128
+ lando.yaml.dump(dest, _.merge(landoFile, config));
129
+ }
130
+
131
+ // Show it
132
+ showInit(lando, options);
128
133
 
129
134
  // Post init event
130
- .then(() => lando.events.emit('post-init', options));
135
+ await lando.events.emit('post-init', options);
131
136
  },
132
137
  };
133
138
  };
package/tasks/rebuild.js CHANGED
@@ -33,16 +33,10 @@ module.exports = lando => {
33
33
  if (app) {
34
34
  console.log(lando.cli.makeArt('appRebuild', {name: app.name, phase: 'pre'}));
35
35
 
36
- // run any setup if we need to but without common plugins or build engine
37
- const sopts = lando?.config?.setup;
38
- sopts.buildEngine = false;
39
- sopts.skipCommonPlugins = true;
40
- sopts.yes = true;
41
- const setupTasks = await lando.getSetupStatus(sopts);
36
+ // run setup if we need to
37
+ await require('../hooks/lando-run-setup')(lando);
42
38
 
43
39
  try {
44
- // run a limited setup if needed
45
- if (setupTasks.length > 0) await lando.setup(sopts);
46
40
  // If user has given us options then set those
47
41
  if (!_.isEmpty(options.service)) app.opts = _.merge({}, app.opts, {services: options.service});
48
42
  // rebuild hero
package/tasks/restart.js CHANGED
@@ -16,17 +16,11 @@ module.exports = lando => {
16
16
  if (app) {
17
17
  console.log(lando.cli.makeArt('appRestart', {name: app.name, phase: 'pre'}));
18
18
 
19
- // run any setup if we need to but without common plugins or build engine
20
- const sopts = lando?.config?.setup;
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 restart
31
25
  await app.restart();
32
26
  // determine legacy settings
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, ['row', 'weight']), columns);
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(`Open a new shell to load the changes!`);
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(`Open a new shell or run ${color.bold(`source ${options.add}`)} to load the changes`);
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 any setup if we need to but without common plugins or build engine
20
- const sopts = lando?.config?.setup;
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'}));
@@ -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
- return app?.containers?.[service] ?? `${app.project}-${service}-1`;
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,
@@ -3,8 +3,8 @@
3
3
  const fs = require('fs');
4
4
  const path = require('path');
5
5
 
6
- module.exports = ({entrypoint, file, installPath}) => {
7
- return [entrypoint, file, installPath]
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))
@@ -27,7 +27,7 @@ const getDockerBin = (bin, base, pathFallback = true) => {
27
27
  }
28
28
  };
29
29
 
30
- module.exports = ({orchestratorVersion = '2.29.2', userConfRoot = os.tmpdir()} = {}) => {
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 (process.platform) {
8
+ const getBuildEngineVersion = (platform = process.landoPlatform ?? process.platform) => {
9
+ switch (platform) {
10
10
  case 'darwin':
11
- return '4.34.3';
11
+ return '4.36.0';
12
12
  case 'linux':
13
13
  return '27.3.1';
14
14
  case 'win32':
15
- return '4.34.3';
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.29.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 (process.platform) {
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
+ };
@@ -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
  };
@@ -29,8 +29,7 @@ module.exports = (paths = [], shell = require('./get-user-shell')()) => {
29
29
 
30
30
  default:
31
31
  return [
32
- ['# Lando'],
33
- [`export PATH="${paths}\${PATH+:$PATH}"; #landopath`, '#landopath'],
32
+ [`export PATH="${paths}:$PATH"; #landopath`, '#landopath'],
34
33
  ];
35
34
  }
36
35
  };
@@ -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 = (format = 'fingerprint') => {
20
+ module.exports = async ({
21
+ format = 'fingerprint',
22
+ platform = process.landoPlatform ?? process.platform,
23
+ }= {}) => {
19
24
  const fingerprints = [];
20
25
 
21
- switch (process.platform) {
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 {systemCertsSync} = require('system-ca');
28
- for (const cert of systemCertsSync()) {
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: ${process.platform}`);
72
+ throw new Error(`Unsupported platform: ${platform}`);
54
73
  }
55
74
  };
@@ -0,0 +1,7 @@
1
+ 'use strict';
2
+
3
+ module.exports = varname => {
4
+ const args = ['-Command', `[Environment]::GetEnvironmentVariable('${varname}')`];
5
+ const {stdout} = require('./spawn-sync-stringer')('powershell.exe', args, {encoding: 'utf-8'});
6
+ return stdout.trim();
7
+ };
@@ -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 (process.platform) {
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')('administrators', user);
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
  }
@@ -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 = process.platform === 'win32' ? win32Cmd(user) : posixCmd(user);
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 (process.platform === 'darwin' || process.platform === 'linux') {
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 (process.platform === 'win32') {
34
- const groups = stdout.split(os.EOL).map(group => group.trim()).filter(group => group !== 'Name' && group !== '----'); // eslint-disable-line max-len
35
- return groups.includes(group);
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?
@@ -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 = engineBin => {
8
- const isWsl = os.release().toLowerCase().includes('microsoft');
9
- // Docker Desktop for Windows keeps the .exe in the same directory as the WSL binary.
10
- return isWsl && fs.existsSync(`${engineBin}.exe`);
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
  };
@@ -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', ['-ExecutionPolicy', 'Bypass', '-File', script].concat(args), options);
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) => {