axodotdev / axodotdev/cargo-dist

npm installer: Windows zip extraction fails under a Restricted PowerShell execution policy (and masks the error)

Open Beginner friendly
#2,437 0 comments 0 reactions 0 assignees View on GitHub
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

Open the contributing 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.