Upgrade azureauth-cli to 0.9.4 with native Linux support#142
Upgrade azureauth-cli to 0.9.4 with native Linux support#142
Conversation
Agent-Logs-Url: https://github.com/microsoft/ado-npm-auth/sessions/3f335052-804f-4397-a3e1-a5754e50896a Co-authored-by: jcreamer898 <472487+jcreamer898@users.noreply.github.com>
| `ado`, | ||
| `pat`, | ||
| `--prompt-hint ${isWsl() ? options.promptHint : `"${options.promptHint}"`}`, // We only use spawn for WSL. spawn does not does not require prompt hint to be wrapped in quotes. exec does. | ||
| `--prompt-hint ${isLinux() ? options.promptHint : `"${options.promptHint}"`}`, // We only use spawn for Linux (includes WSL). spawn does not require prompt hint to be wrapped in quotes. exec does. |
Check warning
Code scanning / CodeQL
Unsafe shell command constructed from library input Medium
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 11 days ago
In general, the safest fix is to avoid going through the shell altogether and instead pass arguments as an array to a function like child_process.spawn/spawnSync or execFile. When that’s not possible, we should not manually build a single command string with interpolated values; instead, parse or quote arguments with a robust library such as shell-quote.
Here, the Linux path is already safe because it uses spawnSync(command[0], command.slice(1), ...) with a proper argument array. The unsafe part is the non‑Linux branch where we call exec(command.join(" "), { env }). The minimal, behavior‑preserving fix is:
- Import
spawnSyncdirectly from"node:child_process"is already done. - Stop joining
commandinto a single string in the non‑Linux branch. - Use
spawnSyncthere as well (like the Linux path), passing theenvfromazureAuthCommand()and encoding"utf-8". - Remove the special quoting logic that embeds quotes into the
--prompt-hintstring for non‑Linux; instead, always pass--prompt-hintas two separate arguments,[ "--prompt-hint", options.promptHint ], which makes quoting unnecessary. This preserves functional behavior while avoiding shell interpretation. - Similarly, split other
--flag valuepairs into distinct array elements instead of interpolated--flag ${value}strings, reducing the chance of accidental changes if someone later reintroduces a join.
These changes are all confined to packages/ado-npm-auth-lib/src/azureauth/ado.ts, specifically around the command array construction and the else branch that currently calls exec.
| @@ -51,28 +51,31 @@ | ||
|
|
||
| const command = [ | ||
| ...authCommand, | ||
| `ado`, | ||
| `pat`, | ||
| `--prompt-hint ${isLinux() ? options.promptHint : `"${options.promptHint}"`}`, // We only use spawn for Linux (includes WSL). spawn does not require prompt hint to be wrapped in quotes. exec does. | ||
| `--organization ${options.organization}`, | ||
| `--display-name ${options.displayName}`, | ||
| ...options.scope.map((scope) => `--scope ${scope}`), | ||
| "ado", | ||
| "pat", | ||
| "--prompt-hint", | ||
| options.promptHint, | ||
| "--organization", | ||
| options.organization, | ||
| "--display-name", | ||
| options.displayName, | ||
| ...options.scope.flatMap((scope) => ["--scope", scope]), | ||
| ]; | ||
|
|
||
| if (options.output) { | ||
| command.push(`--output ${options.output}`); | ||
| command.push("--output", options.output); | ||
| } | ||
|
|
||
| if (options.mode) { | ||
| command.push(`--mode ${options.mode}`); | ||
| command.push("--mode", options.mode); | ||
| } | ||
|
|
||
| if (options.domain) { | ||
| command.push(`--domain ${options.domain}`); | ||
| command.push("--domain", options.domain); | ||
| } | ||
|
|
||
| if (options.timeout) { | ||
| command.push(`--timeout ${options.timeout}`); | ||
| command.push("--timeout", options.timeout); | ||
| } | ||
|
|
||
| try { | ||
| @@ -93,10 +84,15 @@ | ||
| } | ||
| } else { | ||
| try { | ||
| result = await exec(command.join(" "), { env }); | ||
| result = spawnSync(command[0], command.slice(1), { | ||
| encoding: "utf-8", | ||
| env, | ||
| }); | ||
|
|
||
| if (result.stderr && !result.stdout) { | ||
| throw new Error(result.stderr); | ||
| if (result.status !== 0 || (result.stderr && !result.stdout)) { | ||
| throw new Error( | ||
| `Azure Auth failed with exit code ${result.status}: ${result.stderr}`, | ||
| ); | ||
| } | ||
| } catch (error: any) { | ||
| throw new Error( |
Upgrades
azureauth-clifrom0.8.4to0.9.4, which adds native Linux support outside of WSL. Updates all platform-detection logic to treat native Linux and WSL uniformly — callingazureauthdirectly rather than routing throughazureauth.exeornpm exec.Core Changes
node-azureauth/src/install.ts: Version bump to0.9.4; Windows artifact renamed fromwin10-x64.zip→win-x64.zip; removed stalelinux: "azureauth.exe"fromAZUREAUTH_NAME_MAPutils/is-wsl.ts: NewisLinux()export —platform() === "linux"— covers both native Linux and WSL;isWsl()retained for telemetryazureauth-command.ts:isWsl()+["azureauth.exe"]→isLinux()+["azureauth"]ado.ts: AllisWsl()guards replaced withisLinux()(spawn-vs-exec, prompt-hint quoting)is-supported-platform-and-architecture.ts: Addedlinux: ["x64", "arm64"]; removed redundantisWsl() ||OR checkBefore / After:
References and Relevant Issues
azureauth-cli 0.9.4 release: https://github.com/AzureAD/microsoft-authentication-cli/releases/tag/0.9.4
Detailed Description of the Pull Request / Additional comments
Tests updated to mock
isLinux(replacingisWsl), addclearMemotobeforeEachso each test gets a clean command memo, and assertspawnSync("azureauth", [...])rather than the old npm-exec invocation path.Validation Steps Performed
All 22 existing tests pass with no modifications to test counts or test logic — only mock targets and expected values updated to reflect new behavior.
PR Checklist
Warning
Firewall rules blocked me from connecting to one or more addresses (expand for details)
I tried to connect to the following addresses, but was blocked by firewall rules:
https://api.github.com/repos/AzureAD/microsoft-authentication-cli/releases/tags/0.9.4/home/REDACTED/work/_temp/ghcca-node/node/bin/node /home/REDACTED/work/_temp/ghcca-node/node/bin/node --enable-source-maps /home/REDACTED/work/_temp/copilot-developer-action-main/dist/index.js(http block)If you need me to access, download, or install something from one of these locations, you can either:
⚡ Quickly spin up Copilot coding agent tasks from anywhere on your macOS or Windows machine with Raycast.