axodotdev / axodotdev/cargo-dist
npm installer: Windows zip extraction fails under a Restricted PowerShell execution policy (and masks the error)
- Dominant language
- Rust
- Stars
- 2.1k
- Forks
- 149
- Avg merge
- 1d 11h
- Merged PRs (30d)
- 32
Description
### Summary
The generated npm installer (`cargo-dist/templates/installer/npm/binary-install.js`) extracts the Windows `.zip` artifact with `powershell.exe ... Expand-Archive`, but:
1. It does **not** pass `-ExecutionPolicy Bypass`. On a machine whose PowerShell execution policy is `Restricted` (a common Windows client default / locked-down corp setting), the `Microsoft.PowerShell.Archive` module fails to load, so `Expand-Archive` never runs.
2. It treats the `powershell.exe` exit code as success even when `Expand-Archive` throws — so the install **silently reports success** and the failure only surfaces later as `ENOENT` when the run wrapper tries to spawn the never-extracted binary.
This is a follow-up to #2004 / #2005: switching to `Expand-Archive` (#2005) fixed the common "npm install doesn't work on Windows" case, but it still breaks under a `Restricted` policy, and the error is masked.
### Repro
On Windows with `Get-ExecutionPolicy` = `Restricted`:
```
npm install -g
# postinstall prints " has been installed!" and exits 0
--version
# Error: spawnSync ...\node_modules\.bin_real\.exe ENOENT
```
The postinstall's `powershell.exe ... Expand-Archive` writes to stderr:
```
Expand-Archive : ... module 'Microsoft.PowerShell.Archive' ... could not be loaded because running scripts is disabled on this system.
```
…yet `result.status` is `0`, so `binary-install.js` resolves and prints "has been installed!".
### Root cause
```js
result = spawnSync("powershell.exe", [
"-NoProfile",
"-NonInteractive",
"-Command",
`& { param([string]$LiteralPath, [string]$DestinationPath)
Expand-Archive -LiteralPath $LiteralPath -DestinationPath $DestinationPath -Force }`,
tempFile, this.installDirectory,
]);
if (result.status == 0) { resolve(); } // <- 0 even when Expand-Archive threw
```
- No `-ExecutionPolicy Bypass`, so the Archive module won't load under `Restricted`.
- A cmdlet that throws inside the `-Command` script block does not reliably make `powershell.exe` exit non-zero, so `result.status == 0` is not a trustworthy success signal.
### Suggested fix
1. Pass `-ExecutionPolicy Bypass` to the `powershell.exe` invocation.
2. Make extraction failures non-zero, e.g. `try { Expand-Archive ... } catch { Write-Error $_; exit 1 }`.
Verified both on a Restricted-policy Windows machine: with `-ExecutionPolicy Bypass` + the `try/catch`, extraction succeeds, and a genuine failure now yields a non-zero exit instead of a false success.
### Version
cargo-dist 0.32.0 (latest release); the `main` template is unchanged as of this writing.
Contributor guide
Research direction
Start in cargo-dist/templates/installer/npm/binary-install.js and inspect the powershell.exe invocation and result.status handling. Reproduce npm install on Windows with a Restricted execution policy, then verify that extraction succeeds with the bypass setting and that a genuine Expand-Archive failure exits non-zero instead of reporting successful installation.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript, powershell
- Domain
- release
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 82/100