diff --git a/README.md b/README.md index 2a82664..9f715ad 100644 --- a/README.md +++ b/README.md @@ -108,9 +108,10 @@ contains your `docker-compose.yml` / `docker-compose.dev.yml`, or a parent of it > **Non-interactive / AI-agent use.** Commands that would otherwise prompt for confirmation > accept **`-y, --yes`** to proceed with the defaults without asking: `up`, `restart`, `down`, -> `stop-all`, `test`, `import`, `export`, `open`. Combine with `lab help --json` for a -> machine-readable command overview. (Note: writing the hosts file still needs `sudo`/elevation, -> and Doppler-based apps need a pre-authenticated Doppler CLI — neither can be answered by `-y`.) +> `stop-all`, `test`, `import`, `export`, `open`. Run **`lab unlock`** once (see below) so the +> privileged setup (macOS loopback alias, hosts-file write) stops prompting for a `sudo` +> password too. Combine with `lab help --json` for a machine-readable command overview. +> (Doppler-based apps still need a pre-authenticated Doppler CLI.) ### Run & inspect your app @@ -249,6 +250,23 @@ lab run build lab .watch # shorthand for "lab run watch" ``` +#### `unlock` / `lock` _(macOS + Linux)_ +`lab unlock` grants lab **passwordless `sudo` for only its own privileged setup** — the macOS +loopback alias and the hosts-file write — so the CLI can run non-interactively (CI, AI agents, +terminals where nobody can type a password). You are asked for your password **once**. + +How it works: it installs a small **root-owned** helper (`/usr/local/lib/lab-cli/lab-elevate.sh`) +that performs only those two validated actions, and a `visudo`-validated +`/etc/sudoers.d/lab-cli` rule granting `NOPASSWD` for **only that helper** — not blanket root. + +```bash +lab unlock # one password prompt; afterwards `lab up` never prompts for sudo +lab lock # reverts it (removes the sudoers rule + helper) +``` + +On **Windows** lab uses a UAC prompt that can't be pre-authorized this way; run your terminal +“as Administrator” to avoid repeated prompts. + #### `help` Shows the grouped overview of all commands (see [Getting help](#getting-help)). - `--json` — output the overview as JSON for scripts and AI agents. diff --git a/lib/Classes/Api/Network.js b/lib/Classes/Api/Network.js index 359ca3e..596d3e9 100644 --- a/lib/Classes/Api/Network.js +++ b/lib/Classes/Api/Network.js @@ -52,6 +52,7 @@ var __importStar = (this && this.__importStar) || (function () { Object.defineProperty(exports, "__esModule", { value: true }); exports.Network = void 0; const childProcess = __importStar(require("child_process")); +const Unlock_1 = require("./Unlock"); class Network { constructor(context) { this._context = context; @@ -70,7 +71,8 @@ class Network { return; } console.log('A loopback must be registered to handle ip:' + ip + ', this requires root permissions!'); - childProcess.execSync('sudo ifconfig lo0 alias ' + ip); + // Uses the passwordless helper when "lab unlock" is active, otherwise a plain (prompting) sudo. + childProcess.execSync((new Unlock_1.Unlock(this._context)).aliasCommand(ip), { 'stdio': 'inherit' }); if (childProcess.execSync('ifconfig lo0').toString('utf-8').match(pattern)) { console.log('Loopback setup successful!'); return; diff --git a/lib/Classes/Api/Network.js.map b/lib/Classes/Api/Network.js.map index 647870d..3fd0d3c 100644 --- a/lib/Classes/Api/Network.js.map +++ b/lib/Classes/Api/Network.js.map @@ -1 +1 @@ -{"version":3,"file":"Network.js","sourceRoot":"","sources":["../../../src/Classes/Api/Network.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;GAgBG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEH,4DAA8C;AAG9C,MAAa,OAAO;IAIhB,YAAY,OAAmB;QAE3B,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC;IAC5B,CAAC;IAED;;;;OAIG;IACI,+BAA+B,CAAC,EAAU;QAE7C,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC;YAClC,OAAO,CAAC,GAAG,CAAC,8DAA8D,GAAG,EAAE,CAAC,CAAC;YACjF,MAAM,OAAO,GAAG,IAAI,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,uBAAuB,EAAE,MAAM,CAAC,GAAG,UAAU,EAAE,GAAG,CAAC,CAAC;YAC1F,IAAI,YAAY,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC;gBACzE,OAAO,CAAC,GAAG,CAAC,gBAAgB,GAAG,EAAE,GAAG,uBAAuB,CAAC,CAAC;gBAC7D,OAAO;YACX,CAAC;YACD,OAAO,CAAC,GAAG,CAAC,6CAA6C,GAAG,EAAE,GAAG,mCAAmC,CAAC,CAAC;YACtG,YAAY,CAAC,QAAQ,CAAC,0BAA0B,GAAG,EAAE,CAAC,CAAC;YACvD,IAAI,YAAY,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC;gBACzE,OAAO,CAAC,GAAG,CAAC,4BAA4B,CAAC,CAAC;gBAC1C,OAAO;YACX,CAAC;YACD,MAAM,IAAI,KAAK,CAAC,gDAAgD,GAAG,EAAE,CAAC,CAAC;QAC3E,CAAC;IACL,CAAC;CACJ;AAhCD,0BAgCC"} \ No newline at end of file +{"version":3,"file":"Network.js","sourceRoot":"","sources":["../../../src/Classes/Api/Network.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;GAgBG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEH,4DAA8C;AAE9C,qCAAgC;AAEhC,MAAa,OAAO;IAIhB,YAAY,OAAmB;QAE3B,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC;IAC5B,CAAC;IAED;;;;OAIG;IACI,+BAA+B,CAAC,EAAU;QAE7C,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC;YAClC,OAAO,CAAC,GAAG,CAAC,8DAA8D,GAAG,EAAE,CAAC,CAAC;YACjF,MAAM,OAAO,GAAG,IAAI,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,uBAAuB,EAAE,MAAM,CAAC,GAAG,UAAU,EAAE,GAAG,CAAC,CAAC;YAC1F,IAAI,YAAY,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC;gBACzE,OAAO,CAAC,GAAG,CAAC,gBAAgB,GAAG,EAAE,GAAG,uBAAuB,CAAC,CAAC;gBAC7D,OAAO;YACX,CAAC;YACD,OAAO,CAAC,GAAG,CAAC,6CAA6C,GAAG,EAAE,GAAG,mCAAmC,CAAC,CAAC;YACtG,gGAAgG;YAChG,YAAY,CAAC,QAAQ,CAAC,CAAC,IAAI,eAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,YAAY,CAAC,EAAE,CAAC,EAAE,EAAC,OAAO,EAAE,SAAS,EAAC,CAAC,CAAC;YAC1F,IAAI,YAAY,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC;gBACzE,OAAO,CAAC,GAAG,CAAC,4BAA4B,CAAC,CAAC;gBAC1C,OAAO;YACX,CAAC;YACD,MAAM,IAAI,KAAK,CAAC,gDAAgD,GAAG,EAAE,CAAC,CAAC;QAC3E,CAAC;IACL,CAAC;CACJ;AAjCD,0BAiCC"} \ No newline at end of file diff --git a/lib/Classes/Api/Unlock.js b/lib/Classes/Api/Unlock.js new file mode 100644 index 0000000..26aa923 --- /dev/null +++ b/lib/Classes/Api/Unlock.js @@ -0,0 +1,212 @@ +"use strict"; +/* + * Copyright 2020 LABOR.digital + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || (function () { + var ownKeys = function(o) { + ownKeys = Object.getOwnPropertyNames || function (o) { + var ar = []; + for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; + return ar; + }; + return ownKeys(o); + }; + return function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); + __setModuleDefault(result, mod); + return result; + }; +})(); +Object.defineProperty(exports, "__esModule", { value: true }); +exports.Unlock = exports.SUDOERS_PATH = exports.HELPER_PATH = exports.HELPER_DIR = void 0; +const fs = __importStar(require("fs")); +const os = __importStar(require("os")); +const path = __importStar(require("path")); +const ElevatedProcess_1 = require("./ElevatedProcess"); +/** + * Absolute path of the root-owned helper script that performs lab's privileged + * operations. It is intentionally NOT below the (user-writable) npm install dir. + */ +exports.HELPER_DIR = '/usr/local/lib/lab-cli'; +exports.HELPER_PATH = exports.HELPER_DIR + '/lab-elevate.sh'; +exports.SUDOERS_PATH = '/etc/sudoers.d/lab-cli'; +/** + * Manages the optional "unlock" state of the CLI: a scoped, passwordless sudo + * rule that lets lab run its privileged setup (the macOS loopback alias and the + * hosts-file write) WITHOUT a password prompt - so the CLI can be driven + * non-interactively, e.g. by an AI agent that has no access to the shell. + * + * Security model: a root-owned helper script (not user-writable) performs only + * two tightly validated actions, and the sudoers rule grants NOPASSWD for ONLY + * that helper. The user opts in with "lab unlock" (one password prompt) and can + * revert with "lab lock". + */ +class Unlock { + constructor(context) { + this._context = context; + } + /** + * The unlock mechanism relies on sudo + sudoers and is therefore only + * available on macOS and Linux. On Windows lab uses a UAC prompt instead. + */ + isSupported() { + return this._context.platform.isDarwin || this._context.platform.isLinux; + } + /** + * True if lab has been unlocked (the root-owned helper is installed). We only + * probe the helper - the sudoers file in /etc/sudoers.d is usually not + * readable by a normal user. + */ + isInstalled() { + try { + return fs.existsSync(exports.HELPER_PATH); + } + catch (e) { + return false; + } + } + /** + * The shell command lab uses to add the macOS loopback alias. When unlocked it + * goes through the passwordless helper, otherwise through a plain (prompting) sudo. + */ + aliasCommand(ip) { + return this.isInstalled() + ? 'sudo "' + exports.HELPER_PATH + '" alias "' + ip + '"' + : 'sudo ifconfig lo0 alias ' + ip; + } + /** + * The shell command lab uses to copy the prepared hosts file onto the system + * hosts file. Returns null when unlock is not active (callers keep their own + * fallback, e.g. the elevated multi-command used on Windows). + */ + hostsCommand(sourceFile) { + return this.isInstalled() + ? 'sudo "' + exports.HELPER_PATH + '" hosts "' + sourceFile + '"' + : null; + } + /** + * The content of the root-owned helper script. It performs ONLY the two + * privileged actions lab needs and validates its input, so that a NOPASSWD + * rule pointing at it cannot be abused to run arbitrary commands as root. + */ + getHelperScript() { + return [ + '#!/bin/sh', + '# Managed by lab-cli. Do not edit.', + '# Reinstall with "lab unlock", remove with "lab lock".', + 'set -e', + 'action="$1"', + 'case "$action" in', + ' alias)', + ' ip="$2"', + ' # Only ever add loopback (127.0.0.0/8) aliases - never a routable ip.', + ' case "$ip" in', + ' 127.*) exec ifconfig lo0 alias "$ip" ;;', + ' *) echo "lab-elevate: refusing alias for non-loopback ip: $ip" >&2; exit 1 ;;', + ' esac', + ' ;;', + ' hosts)', + ' src="$2"', + ' # Only copy an existing regular file onto the hosts file.', + ' if [ -f "$src" ]; then exec cp "$src" /etc/hosts; fi', + ' echo "lab-elevate: hosts source not found: $src" >&2; exit 1', + ' ;;', + ' *)', + ' echo "lab-elevate: unknown action: $action" >&2; exit 1', + ' ;;', + 'esac', + '' + ].join('\n'); + } + /** + * The content of the /etc/sudoers.d/lab-cli drop-in. Grants the current user + * passwordless sudo for ONLY the lab helper (the helper itself is what limits + * the actual privileged actions). + */ + getSudoersContent() { + return [ + '# Managed by lab-cli. Remove with "lab lock".', + this.getUser() + ' ALL=(root) NOPASSWD: ' + exports.HELPER_PATH + ' *', + '' + ].join('\n'); + } + /** + * The current user name the sudoers rule is written for. + */ + getUser() { + return os.userInfo().username; + } + /** + * Installs the helper + sudoers rule. Requires a single elevated prompt. + * The sudoers file is validated with "visudo -c" BEFORE it is activated, so a + * malformed rule can never break sudo. + */ + install() { + const tmp = this._context.platform.tempDirectory; + const helperTmp = path.join(tmp, 'lab-elevate.sh'); + const sudoersTmp = path.join(tmp, 'lab-cli.sudoers'); + fs.writeFileSync(helperTmp, this.getHelperScript()); + fs.writeFileSync(sudoersTmp, this.getSudoersContent()); + (new ElevatedProcess_1.ElevatedProcess(this._context)).execMultiple([ + 'set -e', + 'mkdir -p "' + exports.HELPER_DIR + '"', + 'cp "' + helperTmp + '" "' + exports.HELPER_PATH + '"', + 'chown 0:0 "' + exports.HELPER_PATH + '"', + 'chmod 755 "' + exports.HELPER_PATH + '"', + 'cp "' + sudoersTmp + '" "' + exports.SUDOERS_PATH + '.tmp"', + 'chown 0:0 "' + exports.SUDOERS_PATH + '.tmp"', + 'chmod 440 "' + exports.SUDOERS_PATH + '.tmp"', + 'if visudo -cf "' + exports.SUDOERS_PATH + '.tmp"; then mv "' + exports.SUDOERS_PATH + '.tmp" "' + exports.SUDOERS_PATH + + '"; else rm -f "' + exports.SUDOERS_PATH + '.tmp"; echo "lab: sudoers validation failed, aborting" >&2; exit 1; fi' + ]); + try { + fs.unlinkSync(helperTmp); + fs.unlinkSync(sudoersTmp); + } + catch (e) { + // best effort cleanup + } + } + /** + * Removes the helper + sudoers rule. Requires a single elevated prompt. + */ + remove() { + (new ElevatedProcess_1.ElevatedProcess(this._context)).execMultiple([ + 'rm -f "' + exports.SUDOERS_PATH + '"', + 'rm -f "' + exports.HELPER_PATH + '"', + 'rmdir "' + exports.HELPER_DIR + '" 2>/dev/null || true' + ]); + } +} +exports.Unlock = Unlock; +//# sourceMappingURL=Unlock.js.map \ No newline at end of file diff --git a/lib/Classes/Api/Unlock.js.map b/lib/Classes/Api/Unlock.js.map new file mode 100644 index 0000000..6bf06b6 --- /dev/null +++ b/lib/Classes/Api/Unlock.js.map @@ -0,0 +1 @@ +{"version":3,"file":"Unlock.js","sourceRoot":"","sources":["../../../src/Classes/Api/Unlock.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/lib/Classes/Command/HelpCommand.js b/lib/Classes/Command/HelpCommand.js index f7305c2..709738e 100644 --- a/lib/Classes/Command/HelpCommand.js +++ b/lib/Classes/Command/HelpCommand.js @@ -30,7 +30,7 @@ const COMMAND_GROUPS = [ { title: 'Run & inspect your app', commands: ['up', 'restart', 'stop', 'down', 'status', 'logs', 'shell', 'open', 'sync'] }, { title: 'Docker engine', commands: ['start-engine', 'stop-engine', 'restart-engine', 'stop-all'] }, { title: 'Project setup & data', commands: ['init', 'import', 'export', 'test', 'installCa'] }, - { title: 'Utilities', commands: ['npm', 'help'] } + { title: 'Utilities', commands: ['npm', 'unlock', 'lock', 'help'] } ]; /** * Renders a full, self-contained overview of everything the CLI can do. diff --git a/lib/Classes/Command/HelpCommand.js.map b/lib/Classes/Command/HelpCommand.js.map index b3cc588..faa600e 100644 --- a/lib/Classes/Command/HelpCommand.js.map +++ b/lib/Classes/Command/HelpCommand.js.map @@ -1 +1 @@ -{"version":3,"file":"HelpCommand.js","sourceRoot":"","sources":["../../../src/Classes/Command/HelpCommand.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"HelpCommand.js","sourceRoot":"","sources":["../../../src/Classes/Command/HelpCommand.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/lib/Classes/Command/UnlockCommand.js b/lib/Classes/Command/UnlockCommand.js new file mode 100644 index 0000000..84377fa --- /dev/null +++ b/lib/Classes/Command/UnlockCommand.js @@ -0,0 +1,68 @@ +"use strict"; +/* + * Copyright 2020 LABOR.digital + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.UnlockCommand = void 0; +const chalk_1 = __importDefault(require("chalk")); +const Unlock_1 = require("../Api/Unlock"); +class UnlockCommand { + /** + * "lab unlock" - installs a scoped, passwordless sudo rule so lab can run its + * privileged setup (macOS loopback alias, hosts-file write) without prompting + * for a password. Useful for CI and AI agents that cannot answer the prompt. + */ + execute(cmd, context) { + const unlock = new Unlock_1.Unlock(context); + if (!unlock.isSupported()) { + console.log(chalk_1.default.yellowBright('On Windows lab uses a UAC prompt for its privileged steps and cannot be pre-authorized this way.\n' + + 'To avoid repeated prompts, run your terminal "as Administrator". "lab unlock" is macOS & Linux only.')); + return Promise.resolve(); + } + if (unlock.isInstalled()) { + console.log('lab is already unlocked. Run "lab lock" to revert.'); + return Promise.resolve(); + } + console.log('This grants passwordless sudo for ONLY lab\'s privileged helper (' + + 'loopback alias + hosts file), so lab can run non-interactively.'); + console.log('You will be asked for your password once to install it. Revert any time with "lab lock".'); + unlock.install(); + console.log(chalk_1.default.greenBright('lab is now unlocked - its privileged setup will no longer prompt for a password.')); + return Promise.resolve(); + } + /** + * "lab lock" - removes what "lab unlock" installed. + */ + lock(cmd, context) { + const unlock = new Unlock_1.Unlock(context); + if (!unlock.isSupported()) { + console.log(chalk_1.default.yellowBright('"lab lock" is macOS & Linux only - there is nothing to remove on Windows.')); + return Promise.resolve(); + } + if (!unlock.isInstalled()) { + console.log('lab is not unlocked - nothing to do.'); + return Promise.resolve(); + } + console.log('Removing the passwordless sudo rule and helper. You may be asked for your password once.'); + unlock.remove(); + console.log(chalk_1.default.greenBright('lab is locked again - privileged steps will prompt for a password as before.')); + return Promise.resolve(); + } +} +exports.UnlockCommand = UnlockCommand; +//# sourceMappingURL=UnlockCommand.js.map \ No newline at end of file diff --git a/lib/Classes/Command/UnlockCommand.js.map b/lib/Classes/Command/UnlockCommand.js.map new file mode 100644 index 0000000..fa1bd38 --- /dev/null +++ b/lib/Classes/Command/UnlockCommand.js.map @@ -0,0 +1 @@ +{"version":3,"file":"UnlockCommand.js","sourceRoot":"","sources":["../../../src/Classes/Command/UnlockCommand.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;GAcG;;;;;;AAEH,kDAA0B;AAE1B,0CAAqC;AAGrC,MAAa,aAAa;IAEtB;;;;OAIG;IACI,OAAO,CAAC,GAAY,EAAE,OAAmB;QAE5C,MAAM,MAAM,GAAG,IAAI,eAAM,CAAC,OAAO,CAAC,CAAC;QAEnC,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,EAAE,CAAC;YACxB,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,YAAY,CAC1B,oGAAoG;gBACpG,sGAAsG,CAAC,CAAC,CAAC;YAC7G,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;QAC7B,CAAC;QAED,IAAI,MAAM,CAAC,WAAW,EAAE,EAAE,CAAC;YACvB,OAAO,CAAC,GAAG,CAAC,oDAAoD,CAAC,CAAC;YAClE,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;QAC7B,CAAC;QAED,OAAO,CAAC,GAAG,CAAC,mEAAmE;YACnE,iEAAiE,CAAC,CAAC;QAC/E,OAAO,CAAC,GAAG,CAAC,0FAA0F,CAAC,CAAC;QACxG,MAAM,CAAC,OAAO,EAAE,CAAC;QACjB,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,WAAW,CAAC,kFAAkF,CAAC,CAAC,CAAC;QACnH,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;IAC7B,CAAC;IAED;;OAEG;IACI,IAAI,CAAC,GAAY,EAAE,OAAmB;QAEzC,MAAM,MAAM,GAAG,IAAI,eAAM,CAAC,OAAO,CAAC,CAAC;QAEnC,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,EAAE,CAAC;YACxB,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,YAAY,CAAC,2EAA2E,CAAC,CAAC,CAAC;YAC7G,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;QAC7B,CAAC;QAED,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,EAAE,CAAC;YACxB,OAAO,CAAC,GAAG,CAAC,sCAAsC,CAAC,CAAC;YACpD,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;QAC7B,CAAC;QAED,OAAO,CAAC,GAAG,CAAC,0FAA0F,CAAC,CAAC;QACxG,MAAM,CAAC,MAAM,EAAE,CAAC;QAChB,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,WAAW,CAAC,8EAA8E,CAAC,CAAC,CAAC;QAC/G,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;IAC7B,CAAC;CACJ;AArDD,sCAqDC"} \ No newline at end of file diff --git a/lib/Classes/Core/Command/DefaultCommands.js b/lib/Classes/Core/Command/DefaultCommands.js index ab4a382..786a302 100644 --- a/lib/Classes/Core/Command/DefaultCommands.js +++ b/lib/Classes/Core/Command/DefaultCommands.js @@ -277,6 +277,15 @@ class DefaultCommands { } ] }); + context.commandRegistry.registerCommand('unlock', '../../Command/UnlockCommand', { + description: 'grants lab passwordless sudo for ONLY its privileged setup (loopback alias + hosts file) so it can run non-interactively (macOS & Linux). Asks for your password once.', + platforms: { windows: true, darwin: true, linux: true } + }); + context.commandRegistry.registerCommand('lock', '../../Command/UnlockCommand', { + action: 'lock', + description: 'reverts "lab unlock" by removing the passwordless sudo rule and helper', + platforms: { windows: true, darwin: true, linux: true } + }); context.commandRegistry.registerCommand('help', '../../Command/HelpCommand', { description: 'shows a grouped overview of all commands and how to use them (use --json for machine-readable output)', platforms: { windows: true, darwin: true, linux: true }, diff --git a/lib/Classes/Core/Command/DefaultCommands.js.map b/lib/Classes/Core/Command/DefaultCommands.js.map index 4dae98e..2c198fc 100644 --- a/lib/Classes/Core/Command/DefaultCommands.js.map +++ b/lib/Classes/Core/Command/DefaultCommands.js.map @@ -1 +1 @@ -{"version":3,"file":"DefaultCommands.js","sourceRoot":"","sources":["../../../../src/Classes/Core/Command/DefaultCommands.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"DefaultCommands.js","sourceRoot":"","sources":["../../../../src/Classes/Core/Command/DefaultCommands.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;GAgBG;;;;;;AAEH,gDAAwB;AAGxB,MAAa,eAAe;IAEjB,MAAM,CAAC,IAAI,CAAC,OAAmB;QAElC,OAAO,CAAC,eAAe,CAAC,eAAe,CACnC,oCAAoC,EACpC,cAAI,CAAC,SAAS,CAAC,cAAI,CAAC,IAAI,CAAC,SAAS,EAAE,0BAA0B,CAAC,CAAC,EAChE;YACI,KAAK,EAAE,KAAK;YACZ,SAAS,EAAE,EAAC,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAC;YACrD,WAAW,EAAE,uIAAuI;YACpJ,cAAc,EAAE,GAAG,EAAE;gBACjB,2DAA2D;gBAC3D,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,WAAW,EAAE,UAAU,IAAI;oBAC1C,IAAI,OAAO,IAAI,CAAC,CAAC,CAAC,KAAK,QAAQ,EAAE,CAAC;wBAC9B,OAAO;oBACX,CAAC;oBACD,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC;wBAC5B,OAAO;oBACX,CAAC;oBACD,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;oBACrC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC;wBAClB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,GAAG,IAAI;qBACnD,CAAC,CAAC;gBACP,CAAC,CAAC,CAAC;YACP,CAAC;SACJ,CAAC,CACL;QAED,OAAO,CAAC,eAAe,CAAC,eAAe,CAAC,IAAI,EAAE,sCAAsC,EAAE;YAClF,KAAK,EAAE,OAAO;YACd,SAAS,EAAE,EAAC,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAC;YACrD,WAAW,EAAE,yEAAyE;YACtF,OAAO,EAAE;gBACL;oBACI,UAAU,EAAE,cAAc;oBAC1B,WAAW,EAAE,yDAAyD;oBACtE,OAAO,EAAE,KAAK;iBACjB;gBACD;oBACI,UAAU,EAAE,YAAY;oBACxB,WAAW,EAAE,yFAAyF;oBACtG,OAAO,EAAE,KAAK;iBACjB;gBACD;oBACI,UAAU,EAAE,WAAW;oBACvB,WAAW,EAAE,2FAA2F;oBACxG,OAAO,EAAE,KAAK;iBACjB;gBACD;oBACI,UAAU,EAAE,cAAc;oBAC1B,WAAW,EAAE,qEAAqE;oBAClF,OAAO,EAAE,KAAK;iBACjB;gBACD,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC;oBAC7B;wBACI,UAAU,EAAE,sBAAsB;wBAClC,WAAW,EAAE,iDAAiD;wBAC9D,OAAO,EAAE,KAAK;qBACjB;iBACJ,CAAC,CAAC,CAAC,EAAE,CAAC;aACV;SACJ,CAAC,CAAC;QAEH,OAAO,CAAC,eAAe,CAAC,eAAe,CAAC,MAAM,EAAE,wCAAwC,EAAE;YACtF,WAAW,EAAE,qDAAqD;YAClE,SAAS,EAAE,EAAC,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAC;YACrD,OAAO,EAAE;gBACL;oBACI,UAAU,EAAE,aAAa;oBACzB,WAAW,EAAE,oDAAoD;oBACjE,OAAO,EAAE,KAAK;iBACjB;aACJ;SACJ,CAAC,CAAC;QAEH,OAAO,CAAC,eAAe,CAAC,eAAe,CAAC,MAAM,EAAE,wCAAwC,EAAE;YACtF,WAAW,EAAE,sEAAsE;YACnF,SAAS,EAAE,EAAC,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAC;YACrD,OAAO,EAAE;gBACL;oBACI,UAAU,EAAE,qBAAqB;oBACjC,WAAW,EAAE,8GAA8G;oBAC3H,UAAU,EAAE,YAAY;oBACxB,OAAO,EAAE,EAAE;iBACd,EAAE;oBACC,UAAU,EAAE,cAAc;oBAC1B,WAAW,EAAE,sCAAsC;oBACnD,OAAO,EAAE,KAAK;iBACjB;aACJ;SACJ,CAAC,CAAC;QAEH,OAAO,CAAC,eAAe,CAAC,eAAe,CAAC,OAAO,EAAE,yCAAyC,EAAE;YACxF,KAAK,EAAE,IAAI;YACX,WAAW,EAAE,wGAAwG;YACrH,SAAS,EAAE,EAAC,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAC;YACrD,OAAO,EAAE;gBACL;oBACI,UAAU,EAAE,iBAAiB;oBAC7B,WAAW,EAAE,uCAAuC;oBACpD,OAAO,EAAE,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,cAAc,EAAE,MAAM,CAAC;iBACtD;gBACD;oBACI,UAAU,EAAE,cAAc;oBAC1B,WAAW,EAAE,uDAAuD;oBACpE,OAAO,EAAE,KAAK;iBACjB;aACJ;SACJ,CAAC,CAAC;QAEH,OAAO,CAAC,eAAe,CAAC,eAAe,CAAC,SAAS,EAAE,2CAA2C,EAAE;YAC5F,WAAW,EAAE,uGAAuG;YACpH,SAAS,EAAE,EAAC,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAC;YACrD,OAAO,EAAE;gBACL;oBACI,UAAU,EAAE,WAAW;oBACvB,WAAW,EAAE,wCAAwC;oBACrD,OAAO,EAAE,KAAK;iBACjB;aACJ;SACJ,CAAC,CAAC;QAEH,OAAO,CAAC,eAAe,CAAC,eAAe,CAAC,MAAM,EAAE,wCAAwC,EAAE;YACtF,WAAW,EAAE,mGAAmG;YAChH,SAAS,EAAE,EAAC,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAC;YACrD,OAAO,EAAE;gBACL;oBACI,UAAU,EAAE,WAAW;oBACvB,WAAW,EAAE,uFAAuF;oBACpG,OAAO,EAAE,KAAK;iBACjB;aACJ;SACJ,CAAC,CAAC;QAEH,OAAO,CAAC,eAAe,CAAC,eAAe,CAAC,MAAM,EAAE,0CAA0C,EAAE;YACxF,WAAW,EAAE,kFAAkF;YAC/F,SAAS,EAAE,EAAC,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAC;YACtD,OAAO,EAAE;gBACL;oBACI,UAAU,EAAE,SAAS;oBACrB,WAAW,EAAE,oGAAoG;oBACjH,OAAO,EAAE,KAAK;iBACjB;aACJ;SACJ,CAAC,CAAC;QAEH,OAAO,CAAC,eAAe,CAAC,eAAe,CAAC,MAAM,EAAE,wCAAwC,EAAE;YACtF,WAAW,EAAE,sEAAsE;YACnF,SAAS,EAAE,EAAC,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAC;YACrD,OAAO,EAAE;gBACL;oBACI,UAAU,EAAE,2BAA2B;oBACvC,WAAW,EAAE,oCAAoC;oBACjD,OAAO,EAAE,OAAO;iBACnB;gBACD;oBACI,UAAU,EAAE,WAAW;oBACvB,WAAW,EAAE,uFAAuF;oBACpG,OAAO,EAAE,KAAK;iBACjB;aACJ;SACJ,CAAC,CAAC;QAEH,OAAO,CAAC,eAAe,CAAC,eAAe,CAAC,UAAU,EAAE,8CAA8C,EAAE;YAChG,WAAW,EAAE,mDAAmD;YAChE,SAAS,EAAE,EAAC,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAC;YACrD,OAAO,EAAE;gBACL;oBACI,UAAU,EAAE,WAAW;oBACvB,WAAW,EAAE,uFAAuF;oBACpG,OAAO,EAAE,KAAK;iBACjB;aACJ;SACJ,CAAC,CAAC;QAEH,OAAO,CAAC,eAAe,CAAC,eAAe,CAAC,cAAc,EAAE,wCAAwC,EAAE;YAC9F,WAAW,EAAE,0DAA0D;YACvE,SAAS,EAAE,EAAC,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAC;SACxD,CAAC,CAAC;QAEH,OAAO,CAAC,eAAe,CAAC,eAAe,CAAC,gBAAgB,EAAE,0CAA0C,EAAE;YAClG,WAAW,EAAE,4BAA4B;YACzC,SAAS,EAAE,EAAC,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAC;SACxD,CAAC,CAAC;QAEH,OAAO,CAAC,eAAe,CAAC,eAAe,CAAC,QAAQ,EAAE,0CAA0C,EAAE;YAC1F,KAAK,EAAE,IAAI;YACX,WAAW,EAAE,+CAA+C;YAC5D,SAAS,EAAE,EAAC,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAC;SACxD,CAAC,CAAC;QAEH,OAAO,CAAC,eAAe,CAAC,eAAe,CAAC,aAAa,EAAE,uCAAuC,EAAE;YAC5F,WAAW,EAAE,qDAAqD;YAClE,SAAS,EAAE,EAAC,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAC;YACrD,OAAO,EAAE;gBACL;oBACI,UAAU,EAAE,SAAS;oBACrB,WAAW,EAAE,mEAAmE;oBAChF,OAAO,EAAE,KAAK;iBACjB;aACJ;SACJ,CAAC,CAAC;QAEH,OAAO,CAAC,eAAe,CAAC,eAAe,CAAC,QAAQ,EAAE,oCAAoC,EAAE;YACpF,WAAW,EAAE,qEAAqE;YAClF,SAAS,EAAE,EAAC,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAC;YACrD,OAAO,EAAE;gBACL;oBACI,UAAU,EAAE,oBAAoB;oBAChC,WAAW,EAAE,yIAAyI;oBACtJ,OAAO,EAAE,KAAK;iBACjB;gBACD;oBACI,UAAU,EAAE,WAAW;oBACvB,WAAW,EAAE,uFAAuF;oBACpG,OAAO,EAAE,KAAK;iBACjB;aACJ;SACJ,CAAC,CAAC;QAEH,OAAO,CAAC,eAAe,CAAC,eAAe,CAAC,QAAQ,EAAE,oCAAoC,EAAE;YACpF,WAAW,EAAE,qEAAqE;YAClF,SAAS,EAAE,EAAC,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAC;YACrD,OAAO,EAAE;gBACL;oBACI,UAAU,EAAE,kBAAkB;oBAC9B,WAAW,EAAE,qHAAqH;oBAClI,OAAO,EAAE,KAAK;iBACjB;gBACD;oBACI,UAAU,EAAE,WAAW;oBACvB,WAAW,EAAE,uFAAuF;oBACpG,OAAO,EAAE,KAAK;iBACjB;aACJ;SACJ,CAAC,CAAC;QAEH,OAAO,CAAC,eAAe,CAAC,eAAe,CAAC,MAAM,EAAE,kCAAkC,EAAE;YAChF,WAAW,EAAE,6DAA6D;YAC1E,SAAS,EAAE,EAAC,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAC;YACrD,OAAO,EAAE;gBACL;oBACI,UAAU,EAAE,mBAAmB;oBAC/B,WAAW,EAAE,mEAAmE;iBACnF;gBACD;oBACI,UAAU,EAAE,iCAAiC;oBAC7C,WAAW,EAAE,oCAAoC;iBACpD;gBACD;oBACI,UAAU,EAAE,aAAa;oBACzB,WAAW,EAAE,yDAAyD;oBACtE,OAAO,EAAE,KAAK;iBACjB;aACJ;SACJ,CAAC,CAAC;QAEH,OAAO,CAAC,eAAe,CAAC,eAAe,CAAC,WAAW,EAAE,gCAAgC,EAAE;YACnF,WAAW,EAAE,iFAAiF;YAC9F,SAAS,EAAE,EAAC,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAC;SACxD,CAAC,CAAC;QAEH,OAAO,CAAC,eAAe,CAAC,eAAe,CAAC,MAAM,EAAE,kCAAkC,EAAE;YAChF,WAAW,EAAE,oEAAoE;YACjF,SAAS,EAAE,EAAC,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAC;YACrD,OAAO,EAAE;gBACL;oBACI,UAAU,EAAE,cAAc;oBAC1B,WAAW,EAAE,uHAAuH;oBACpI,OAAO,EAAE,KAAK;iBACjB;gBACD;oBACI,UAAU,EAAE,WAAW;oBACvB,WAAW,EAAE,uFAAuF;oBACpG,OAAO,EAAE,KAAK;iBACjB;aACJ;SACJ,CAAC,CAAC;QAEH,OAAO,CAAC,eAAe,CAAC,eAAe,CAAC,QAAQ,EAAE,6BAA6B,EAAE;YAC7E,WAAW,EAAE,wKAAwK;YACrL,SAAS,EAAE,EAAC,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAC;SACxD,CAAC,CAAC;QAEH,OAAO,CAAC,eAAe,CAAC,eAAe,CAAC,MAAM,EAAE,6BAA6B,EAAE;YAC3E,MAAM,EAAE,MAAM;YACd,WAAW,EAAE,wEAAwE;YACrF,SAAS,EAAE,EAAC,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAC;SACxD,CAAC,CAAC;QAEH,OAAO,CAAC,eAAe,CAAC,eAAe,CAAC,MAAM,EAAE,2BAA2B,EAAE;YACzE,WAAW,EAAE,uGAAuG;YACpH,SAAS,EAAE,EAAC,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAC;YACrD,OAAO,EAAE;gBACL;oBACI,UAAU,EAAE,QAAQ;oBACpB,WAAW,EAAE,sEAAsE;oBACnF,OAAO,EAAE,KAAK;iBACjB;aACJ;SACJ,CAAC,CAAC;QAEH,OAAO,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IACpC,CAAC;CACJ;AAjTD,0CAiTC"} \ No newline at end of file diff --git a/lib/Classes/Core/DockerApp/DockerHosts.js b/lib/Classes/Core/DockerApp/DockerHosts.js index ec60cd2..b364af1 100644 --- a/lib/Classes/Core/DockerApp/DockerHosts.js +++ b/lib/Classes/Core/DockerApp/DockerHosts.js @@ -54,7 +54,9 @@ const ForEachHelper_1 = require("../Utils/ForEachHelper"); */ const fs = __importStar(require("fs")); const path = __importStar(require("path")); +const childProcess = __importStar(require("child_process")); const ElevatedProcess_1 = require("../../Api/ElevatedProcess"); +const Unlock_1 = require("../../Api/Unlock"); class DockerHosts { /** * DockerHosts constructor @@ -174,11 +176,19 @@ class DockerHosts { const tmpFile = path.join(this._context.platform.tempDirectory, 'lab-tmp-hosts.txt'); fs.writeFileSync(tmpFile, content); this._isDirty = false; - // Copy the hosts to the destination using elevation - (new ElevatedProcess_1.ElevatedProcess(this._context)).execMultiple([ - this._context.platform.choose({ windows: 'copy /Y', linux: 'cp' }) + - ' "' + tmpFile + '" "' + this._filename + '"' - ]); + // Copy the hosts file to its destination using elevation. + // When "lab unlock" is active (macOS & Linux) this goes through the + // passwordless helper; otherwise it falls back to a prompting elevation. + const hostsCommand = (new Unlock_1.Unlock(this._context)).hostsCommand(tmpFile); + if (hostsCommand !== null) { + childProcess.execSync(hostsCommand, { 'stdio': 'inherit' }); + } + else { + (new ElevatedProcess_1.ElevatedProcess(this._context)).execMultiple([ + this._context.platform.choose({ windows: 'copy /Y', linux: 'cp' }) + + ' "' + tmpFile + '" "' + this._filename + '"' + ]); + } } /** * Reads the contents of the hosts file into the memory lists diff --git a/lib/Classes/Core/DockerApp/DockerHosts.js.map b/lib/Classes/Core/DockerApp/DockerHosts.js.map index 4541c1b..858fc52 100644 --- a/lib/Classes/Core/DockerApp/DockerHosts.js.map +++ b/lib/Classes/Core/DockerApp/DockerHosts.js.map @@ -1 +1 @@ -{"version":3,"file":"DockerHosts.js","sourceRoot":"","sources":["../../../../src/Classes/Core/DockerApp/DockerHosts.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"DockerHosts.js","sourceRoot":"","sources":["../../../../src/Classes/Core/DockerApp/DockerHosts.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/src/Classes/Api/Network.ts b/src/Classes/Api/Network.ts index dc10c08..8a6b9d9 100644 --- a/src/Classes/Api/Network.ts +++ b/src/Classes/Api/Network.ts @@ -18,6 +18,7 @@ import * as childProcess from 'child_process'; import {AppContext} from '../Core/AppContext'; +import {Unlock} from './Unlock'; export class Network { @@ -43,7 +44,8 @@ export class Network return; } console.log('A loopback must be registered to handle ip:' + ip + ', this requires root permissions!'); - childProcess.execSync('sudo ifconfig lo0 alias ' + ip); + // Uses the passwordless helper when "lab unlock" is active, otherwise a plain (prompting) sudo. + childProcess.execSync((new Unlock(this._context)).aliasCommand(ip), {'stdio': 'inherit'}); if (childProcess.execSync('ifconfig lo0').toString('utf-8').match(pattern)) { console.log('Loopback setup successful!'); return; diff --git a/src/Classes/Api/Unlock.ts b/src/Classes/Api/Unlock.ts new file mode 100644 index 0000000..7fb9b62 --- /dev/null +++ b/src/Classes/Api/Unlock.ts @@ -0,0 +1,201 @@ +/* + * Copyright 2020 LABOR.digital + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import * as childProcess from 'child_process'; +import * as fs from 'fs'; +import * as os from 'os'; +import * as path from 'path'; +import {AppContext} from '../Core/AppContext'; +import {ElevatedProcess} from './ElevatedProcess'; + +/** + * Absolute path of the root-owned helper script that performs lab's privileged + * operations. It is intentionally NOT below the (user-writable) npm install dir. + */ +export const HELPER_DIR = '/usr/local/lib/lab-cli'; +export const HELPER_PATH = HELPER_DIR + '/lab-elevate.sh'; +export const SUDOERS_PATH = '/etc/sudoers.d/lab-cli'; + +/** + * Manages the optional "unlock" state of the CLI: a scoped, passwordless sudo + * rule that lets lab run its privileged setup (the macOS loopback alias and the + * hosts-file write) WITHOUT a password prompt - so the CLI can be driven + * non-interactively, e.g. by an AI agent that has no access to the shell. + * + * Security model: a root-owned helper script (not user-writable) performs only + * two tightly validated actions, and the sudoers rule grants NOPASSWD for ONLY + * that helper. The user opts in with "lab unlock" (one password prompt) and can + * revert with "lab lock". + */ +export class Unlock +{ + protected _context: AppContext; + + public constructor(context: AppContext) + { + this._context = context; + } + + /** + * The unlock mechanism relies on sudo + sudoers and is therefore only + * available on macOS and Linux. On Windows lab uses a UAC prompt instead. + */ + public isSupported(): boolean + { + return this._context.platform.isDarwin || this._context.platform.isLinux; + } + + /** + * True if lab has been unlocked (the root-owned helper is installed). We only + * probe the helper - the sudoers file in /etc/sudoers.d is usually not + * readable by a normal user. + */ + public isInstalled(): boolean + { + try { + return fs.existsSync(HELPER_PATH); + } catch (e) { + return false; + } + } + + /** + * The shell command lab uses to add the macOS loopback alias. When unlocked it + * goes through the passwordless helper, otherwise through a plain (prompting) sudo. + */ + public aliasCommand(ip: string): string + { + return this.isInstalled() + ? 'sudo "' + HELPER_PATH + '" alias "' + ip + '"' + : 'sudo ifconfig lo0 alias ' + ip; + } + + /** + * The shell command lab uses to copy the prepared hosts file onto the system + * hosts file. Returns null when unlock is not active (callers keep their own + * fallback, e.g. the elevated multi-command used on Windows). + */ + public hostsCommand(sourceFile: string): string | null + { + return this.isInstalled() + ? 'sudo "' + HELPER_PATH + '" hosts "' + sourceFile + '"' + : null; + } + + /** + * The content of the root-owned helper script. It performs ONLY the two + * privileged actions lab needs and validates its input, so that a NOPASSWD + * rule pointing at it cannot be abused to run arbitrary commands as root. + */ + public getHelperScript(): string + { + return [ + '#!/bin/sh', + '# Managed by lab-cli. Do not edit.', + '# Reinstall with "lab unlock", remove with "lab lock".', + 'set -e', + 'action="$1"', + 'case "$action" in', + ' alias)', + ' ip="$2"', + ' # Only ever add loopback (127.0.0.0/8) aliases - never a routable ip.', + ' case "$ip" in', + ' 127.*) exec ifconfig lo0 alias "$ip" ;;', + ' *) echo "lab-elevate: refusing alias for non-loopback ip: $ip" >&2; exit 1 ;;', + ' esac', + ' ;;', + ' hosts)', + ' src="$2"', + ' # Only copy an existing regular file onto the hosts file.', + ' if [ -f "$src" ]; then exec cp "$src" /etc/hosts; fi', + ' echo "lab-elevate: hosts source not found: $src" >&2; exit 1', + ' ;;', + ' *)', + ' echo "lab-elevate: unknown action: $action" >&2; exit 1', + ' ;;', + 'esac', + '' + ].join('\n'); + } + + /** + * The content of the /etc/sudoers.d/lab-cli drop-in. Grants the current user + * passwordless sudo for ONLY the lab helper (the helper itself is what limits + * the actual privileged actions). + */ + public getSudoersContent(): string + { + return [ + '# Managed by lab-cli. Remove with "lab lock".', + this.getUser() + ' ALL=(root) NOPASSWD: ' + HELPER_PATH + ' *', + '' + ].join('\n'); + } + + /** + * The current user name the sudoers rule is written for. + */ + public getUser(): string + { + return os.userInfo().username; + } + + /** + * Installs the helper + sudoers rule. Requires a single elevated prompt. + * The sudoers file is validated with "visudo -c" BEFORE it is activated, so a + * malformed rule can never break sudo. + */ + public install(): void + { + const tmp = this._context.platform.tempDirectory; + const helperTmp = path.join(tmp, 'lab-elevate.sh'); + const sudoersTmp = path.join(tmp, 'lab-cli.sudoers'); + fs.writeFileSync(helperTmp, this.getHelperScript()); + fs.writeFileSync(sudoersTmp, this.getSudoersContent()); + + (new ElevatedProcess(this._context)).execMultiple([ + 'set -e', + 'mkdir -p "' + HELPER_DIR + '"', + 'cp "' + helperTmp + '" "' + HELPER_PATH + '"', + 'chown 0:0 "' + HELPER_PATH + '"', + 'chmod 755 "' + HELPER_PATH + '"', + 'cp "' + sudoersTmp + '" "' + SUDOERS_PATH + '.tmp"', + 'chown 0:0 "' + SUDOERS_PATH + '.tmp"', + 'chmod 440 "' + SUDOERS_PATH + '.tmp"', + 'if visudo -cf "' + SUDOERS_PATH + '.tmp"; then mv "' + SUDOERS_PATH + '.tmp" "' + SUDOERS_PATH + + '"; else rm -f "' + SUDOERS_PATH + '.tmp"; echo "lab: sudoers validation failed, aborting" >&2; exit 1; fi' + ]); + + try { + fs.unlinkSync(helperTmp); + fs.unlinkSync(sudoersTmp); + } catch (e) { + // best effort cleanup + } + } + + /** + * Removes the helper + sudoers rule. Requires a single elevated prompt. + */ + public remove(): void + { + (new ElevatedProcess(this._context)).execMultiple([ + 'rm -f "' + SUDOERS_PATH + '"', + 'rm -f "' + HELPER_PATH + '"', + 'rmdir "' + HELPER_DIR + '" 2>/dev/null || true' + ]); + } +} diff --git a/src/Classes/Command/HelpCommand.ts b/src/Classes/Command/HelpCommand.ts index bcdb5be..a75f3d5 100644 --- a/src/Classes/Command/HelpCommand.ts +++ b/src/Classes/Command/HelpCommand.ts @@ -56,7 +56,7 @@ const COMMAND_GROUPS: Array<{title: string; commands: Array}> = [ {title: 'Run & inspect your app', commands: ['up', 'restart', 'stop', 'down', 'status', 'logs', 'shell', 'open', 'sync']}, {title: 'Docker engine', commands: ['start-engine', 'stop-engine', 'restart-engine', 'stop-all']}, {title: 'Project setup & data', commands: ['init', 'import', 'export', 'test', 'installCa']}, - {title: 'Utilities', commands: ['npm', 'help']} + {title: 'Utilities', commands: ['npm', 'unlock', 'lock', 'help']} ]; /** diff --git a/src/Classes/Command/UnlockCommand.ts b/src/Classes/Command/UnlockCommand.ts new file mode 100644 index 0000000..e90676a --- /dev/null +++ b/src/Classes/Command/UnlockCommand.ts @@ -0,0 +1,75 @@ +/* + * Copyright 2020 LABOR.digital + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import chalk from 'chalk'; +import {Command} from 'commander'; +import {Unlock} from '../Api/Unlock'; +import {AppContext} from '../Core/AppContext'; + +export class UnlockCommand +{ + /** + * "lab unlock" - installs a scoped, passwordless sudo rule so lab can run its + * privileged setup (macOS loopback alias, hosts-file write) without prompting + * for a password. Useful for CI and AI agents that cannot answer the prompt. + */ + public execute(cmd: Command, context: AppContext): Promise + { + const unlock = new Unlock(context); + + if (!unlock.isSupported()) { + console.log(chalk.yellowBright( + 'On Windows lab uses a UAC prompt for its privileged steps and cannot be pre-authorized this way.\n' + + 'To avoid repeated prompts, run your terminal "as Administrator". "lab unlock" is macOS & Linux only.')); + return Promise.resolve(); + } + + if (unlock.isInstalled()) { + console.log('lab is already unlocked. Run "lab lock" to revert.'); + return Promise.resolve(); + } + + console.log('This grants passwordless sudo for ONLY lab\'s privileged helper (' + + 'loopback alias + hosts file), so lab can run non-interactively.'); + console.log('You will be asked for your password once to install it. Revert any time with "lab lock".'); + unlock.install(); + console.log(chalk.greenBright('lab is now unlocked - its privileged setup will no longer prompt for a password.')); + return Promise.resolve(); + } + + /** + * "lab lock" - removes what "lab unlock" installed. + */ + public lock(cmd: Command, context: AppContext): Promise + { + const unlock = new Unlock(context); + + if (!unlock.isSupported()) { + console.log(chalk.yellowBright('"lab lock" is macOS & Linux only - there is nothing to remove on Windows.')); + return Promise.resolve(); + } + + if (!unlock.isInstalled()) { + console.log('lab is not unlocked - nothing to do.'); + return Promise.resolve(); + } + + console.log('Removing the passwordless sudo rule and helper. You may be asked for your password once.'); + unlock.remove(); + console.log(chalk.greenBright('lab is locked again - privileged steps will prompt for a password as before.')); + return Promise.resolve(); + } +} diff --git a/src/Classes/Core/Command/DefaultCommands.ts b/src/Classes/Core/Command/DefaultCommands.ts index c10172b..b831287 100644 --- a/src/Classes/Core/Command/DefaultCommands.ts +++ b/src/Classes/Core/Command/DefaultCommands.ts @@ -299,6 +299,17 @@ export class DefaultCommands ] }); + context.commandRegistry.registerCommand('unlock', '../../Command/UnlockCommand', { + description: 'grants lab passwordless sudo for ONLY its privileged setup (loopback alias + hosts file) so it can run non-interactively (macOS & Linux). Asks for your password once.', + platforms: {windows: true, darwin: true, linux: true} + }); + + context.commandRegistry.registerCommand('lock', '../../Command/UnlockCommand', { + action: 'lock', + description: 'reverts "lab unlock" by removing the passwordless sudo rule and helper', + platforms: {windows: true, darwin: true, linux: true} + }); + context.commandRegistry.registerCommand('help', '../../Command/HelpCommand', { description: 'shows a grouped overview of all commands and how to use them (use --json for machine-readable output)', platforms: {windows: true, darwin: true, linux: true}, diff --git a/src/Classes/Core/DockerApp/DockerHosts.ts b/src/Classes/Core/DockerApp/DockerHosts.ts index 96fdcb1..d04ab66 100644 --- a/src/Classes/Core/DockerApp/DockerHosts.ts +++ b/src/Classes/Core/DockerApp/DockerHosts.ts @@ -20,7 +20,9 @@ import {forEach} from '../Utils/ForEachHelper'; import * as fs from 'fs'; import * as path from 'path'; +import * as childProcess from 'child_process'; import {ElevatedProcess} from '../../Api/ElevatedProcess'; +import {Unlock} from '../../Api/Unlock'; import {AppContext} from '../AppContext'; export class DockerHosts @@ -193,11 +195,18 @@ export class DockerHosts fs.writeFileSync(tmpFile, content); this._isDirty = false; - // Copy the hosts to the destination using elevation - (new ElevatedProcess(this._context)).execMultiple([ - this._context.platform.choose({windows: 'copy /Y', linux: 'cp'}) + - ' "' + tmpFile + '" "' + this._filename + '"' - ]); + // Copy the hosts file to its destination using elevation. + // When "lab unlock" is active (macOS & Linux) this goes through the + // passwordless helper; otherwise it falls back to a prompting elevation. + const hostsCommand = (new Unlock(this._context)).hostsCommand(tmpFile); + if (hostsCommand !== null) { + childProcess.execSync(hostsCommand, {'stdio': 'inherit'}); + } else { + (new ElevatedProcess(this._context)).execMultiple([ + this._context.platform.choose({windows: 'copy /Y', linux: 'cp'}) + + ' "' + tmpFile + '" "' + this._filename + '"' + ]); + } } /** diff --git a/test/Unlock.test.ts b/test/Unlock.test.ts new file mode 100644 index 0000000..942ca75 --- /dev/null +++ b/test/Unlock.test.ts @@ -0,0 +1,80 @@ +import * as fs from 'fs'; +import { Unlock, HELPER_PATH, SUDOERS_PATH } from '../src/Classes/Api/Unlock'; +import { ElevatedProcess } from '../src/Classes/Api/ElevatedProcess'; + +jest.mock('fs'); +jest.mock('os', () => ({ userInfo: () => ({ username: 'tester' }) })); +jest.mock('../src/Classes/Api/ElevatedProcess'); + +function ctx(platform: any): any { + return { + platform: { + isDarwin: false, isLinux: false, isWindows: false, + tempDirectory: '/tmp', choose: (o: any) => o.linux, + ...platform + } + }; +} + +describe('Unlock', () => { + let execMultiple: jest.Mock; + + beforeEach(() => { + jest.clearAllMocks(); + execMultiple = jest.fn(); + (ElevatedProcess as unknown as jest.Mock).mockImplementation(() => ({ execMultiple })); + (fs.writeFileSync as jest.Mock).mockImplementation(() => {}); + (fs.unlinkSync as jest.Mock).mockImplementation(() => {}); + }); + afterEach(() => jest.restoreAllMocks()); + + it('is supported on macOS and Linux, not Windows', () => { + expect(new Unlock(ctx({ isDarwin: true })).isSupported()).toBe(true); + expect(new Unlock(ctx({ isLinux: true })).isSupported()).toBe(true); + expect(new Unlock(ctx({ isWindows: true })).isSupported()).toBe(false); + }); + + it('helper script only allows loopback aliases and hosts copies', () => { + const script = new Unlock(ctx({ isDarwin: true })).getHelperScript(); + expect(script).toContain('ifconfig lo0 alias'); + expect(script).toContain('127.*)'); + expect(script).toContain('cp "$src" /etc/hosts'); + expect(script).toContain('refusing alias for non-loopback'); + }); + + it('sudoers content scopes NOPASSWD to the helper for the current user', () => { + const content = new Unlock(ctx({ isDarwin: true })).getSudoersContent(); + expect(content).toContain('tester ALL=(root) NOPASSWD: ' + HELPER_PATH + ' *'); + }); + + it('routes commands through the helper only when installed', () => { + (fs.existsSync as jest.Mock).mockReturnValue(false); + const locked = new Unlock(ctx({ isDarwin: true })); + expect(locked.aliasCommand('127.88.0.1')).toBe('sudo ifconfig lo0 alias 127.88.0.1'); + expect(locked.hostsCommand('/tmp/h')).toBeNull(); + + (fs.existsSync as jest.Mock).mockReturnValue(true); + const unlocked = new Unlock(ctx({ isDarwin: true })); + expect(unlocked.aliasCommand('127.88.0.1')).toBe('sudo "' + HELPER_PATH + '" alias "127.88.0.1"'); + expect(unlocked.hostsCommand('/tmp/h')).toBe('sudo "' + HELPER_PATH + '" hosts "/tmp/h"'); + }); + + it('install writes temp files and installs via a single visudo-validated elevated block', () => { + (fs.existsSync as jest.Mock).mockReturnValue(false); + new Unlock(ctx({ isDarwin: true })).install(); + + expect(fs.writeFileSync).toHaveBeenCalledTimes(2); + expect(execMultiple).toHaveBeenCalledTimes(1); + const cmds = (execMultiple.mock.calls[0][0] as string[]).join('\n'); + expect(cmds).toContain('visudo -cf'); + expect(cmds).toContain(HELPER_PATH); + expect(cmds).toContain(SUDOERS_PATH); + }); + + it('remove deletes the sudoers rule and helper via elevation', () => { + new Unlock(ctx({ isDarwin: true })).remove(); + const cmds = (execMultiple.mock.calls[0][0] as string[]).join('\n'); + expect(cmds).toContain('rm -f "' + SUDOERS_PATH + '"'); + expect(cmds).toContain('rm -f "' + HELPER_PATH + '"'); + }); +}); diff --git a/test/UnlockCommand.test.ts b/test/UnlockCommand.test.ts new file mode 100644 index 0000000..259fbb6 --- /dev/null +++ b/test/UnlockCommand.test.ts @@ -0,0 +1,54 @@ +import { Command } from 'commander'; +import { UnlockCommand } from '../src/Classes/Command/UnlockCommand'; +import { AppContext } from '../src/Classes/Core/AppContext'; +import { Unlock } from '../src/Classes/Api/Unlock'; + +jest.mock('../src/Classes/Api/Unlock'); + +describe('UnlockCommand', () => { + let mockUnlock: any; + const cmd = {} as Command; + const ctx = {} as AppContext; + + beforeEach(() => { + jest.clearAllMocks(); + jest.spyOn(console, 'log').mockImplementation(() => undefined); + mockUnlock = { + isSupported: jest.fn().mockReturnValue(true), + isInstalled: jest.fn().mockReturnValue(false), + install: jest.fn(), + remove: jest.fn() + }; + (Unlock as unknown as jest.Mock).mockImplementation(() => mockUnlock); + }); + afterEach(() => jest.restoreAllMocks()); + + it('unlock installs when supported and not yet unlocked', async () => { + await new UnlockCommand().execute(cmd, ctx); + expect(mockUnlock.install).toHaveBeenCalled(); + }); + + it('unlock warns and does nothing on an unsupported platform', async () => { + mockUnlock.isSupported.mockReturnValue(false); + await new UnlockCommand().execute(cmd, ctx); + expect(mockUnlock.install).not.toHaveBeenCalled(); + }); + + it('unlock skips install when already unlocked', async () => { + mockUnlock.isInstalled.mockReturnValue(true); + await new UnlockCommand().execute(cmd, ctx); + expect(mockUnlock.install).not.toHaveBeenCalled(); + }); + + it('lock removes when unlocked', async () => { + mockUnlock.isInstalled.mockReturnValue(true); + await new UnlockCommand().lock(cmd, ctx); + expect(mockUnlock.remove).toHaveBeenCalled(); + }); + + it('lock does nothing when not unlocked', async () => { + mockUnlock.isInstalled.mockReturnValue(false); + await new UnlockCommand().lock(cmd, ctx); + expect(mockUnlock.remove).not.toHaveBeenCalled(); + }); +}); diff --git a/test/__mocks__/chalk.js b/test/__mocks__/chalk.js index 5190756..011e188 100644 --- a/test/__mocks__/chalk.js +++ b/test/__mocks__/chalk.js @@ -1,6 +1,9 @@ module.exports = { redBright: (str) => str, greenBright: (str) => str, + yellowBright: (str) => str, + blueBright: (str) => str, + cyanBright: (str) => str, yellow: (str) => str, blue: (str) => str, cyan: (str) => str,