Compare commits

..
Author SHA1 Message Date
copilot-swe-agent[bot] 42bb45f289 Initial plan 2026-07-02 17:33:13 +00:00
Jordan Harband 419ff4efec [actions] update workflows
Tests: fast / fast (sh, mawk) (push) Has been cancelled
urchin tests / tests (bash, sourcing) (push) Has been cancelled
urchin tests / tests (dash, installation_iojs) (push) Has been cancelled
urchin tests / tests (dash, slow) (push) Has been cancelled
urchin tests / tests (dash, sourcing) (push) Has been cancelled
urchin tests / tests (sh, installation_iojs) (push) Has been cancelled
urchin tests / tests (sh, slow) (push) Has been cancelled
urchin tests / tests (sh, sourcing) (push) Has been cancelled
urchin tests / tests (zsh, installation_iojs) (push) Has been cancelled
urchin tests / tests (zsh, slow) (push) Has been cancelled
urchin tests / tests (zsh, sourcing) (push) Has been cancelled
update readme TOC / update readme TOC (push) Has been cancelled
Tests on Windows: `nvm install` / MSYS fail prefix nvm install (push) Has been cancelled
Tests on Windows: `nvm install` / MSYS nvm install (--lts) (push) Has been cancelled
Tests on Windows: `nvm install` / MSYS nvm install (--no-progress 10) (push) Has been cancelled
Tests on Windows: `nvm install` / Cygwin nvm install (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 10, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 10, Ubuntu-18.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 10, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 12, Ubuntu-18.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 12, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 14, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 14, Ubuntu-18.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 14, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 16, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 16, Ubuntu-18.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 16, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 18, Debian) (push) Has been cancelled
Code scanning - action / CodeQL-Build (push) Has been cancelled
Tests: `nvm install-latest-npm` / matrix (push) Has been cancelled
Tests: linting / eclint (push) Has been cancelled
Tests: linting / dockerfile_lint (push) Has been cancelled
Tests: linting / doctoc (push) Has been cancelled
Tests: linting / test_naming (push) Has been cancelled
Tests: nvm install with set -e / matrix (push) Has been cancelled
Tests: release process / release (push) Has been cancelled
Tests: shellcheck / shellcheck_matrix (bash_completion, bash) (push) Has been cancelled
Tests: shellcheck / shellcheck_matrix (install.sh, bash) (push) Has been cancelled
Tests: shellcheck / shellcheck_matrix (nvm-exec, bash) (push) Has been cancelled
Tests: shellcheck / shellcheck_matrix (nvm.sh, bash) (push) Has been cancelled
Tests: shellcheck / shellcheck_matrix (nvm.sh, dash) (push) Has been cancelled
Tests: shellcheck / shellcheck_matrix (nvm.sh, ksh) (push) Has been cancelled
Tests: shellcheck / shellcheck_matrix (nvm.sh, sh) (push) Has been cancelled
Tests: installation_iojs / installation_iojs without curl (bash) (push) Has been cancelled
Tests: fast / fast (bash, gawk) (push) Has been cancelled
Tests: fast / fast (dash, gawk) (push) Has been cancelled
Tests: fast / fast (sh, gawk) (push) Has been cancelled
Tests: fast / fast (zsh, gawk) (push) Has been cancelled
Tests: fast / fast (bash, mawk) (push) Has been cancelled
Tests: fast / fast (dash, mawk) (push) Has been cancelled
Tests: installation_iojs / installation_iojs without curl (dash) (push) Has been cancelled
Tests: installation_iojs / installation_iojs without curl (sh) (push) Has been cancelled
Tests: installation_iojs / installation_iojs without curl (zsh) (push) Has been cancelled
Tests: installation_node / installation_node (bash) (push) Has been cancelled
Tests: installation_node / installation_node (bash, without curl) (push) Has been cancelled
Tests: installation_node / installation_node (dash) (push) Has been cancelled
Tests: installation_node / installation_node (dash, without curl) (push) Has been cancelled
Tests: installation_node / installation_node (sh) (push) Has been cancelled
Tests: installation_node / installation_node (sh, without curl) (push) Has been cancelled
Tests: installation_node / installation_node (zsh) (push) Has been cancelled
Tests: installation_node / installation_node (zsh, without curl) (push) Has been cancelled
Tests: xenial / xenial (bash) (push) Has been cancelled
Tests: xenial / xenial (dash) (push) Has been cancelled
Tests: xenial / xenial (sh) (push) Has been cancelled
Tests: xenial / xenial (zsh) (push) Has been cancelled
urchin tests / tests (bash, install_script) (push) Has been cancelled
urchin tests / tests (bash, installation_iojs) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 12, Ubuntu-18.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 12, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 16, Alpine) (push) Has been cancelled
Tests: nvm install with set -e / test (push) Has been cancelled
Tests: nvm install with set -e / finisher (push) Has been cancelled
Tests: shellcheck / shellcheck (push) Has been cancelled
urchin tests / tests (bash, slow) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 21, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 10, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 10, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 12, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 14, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 14, Ubuntu-18.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 14, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 16, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 16, Ubuntu-18.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 16, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 18, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 18, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 21, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 21, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, --lts, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 10, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 11, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 12, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 14, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 18, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 21, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, --lts, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 10, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 11, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 12, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 14, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 16, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 18, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 21, Alpine) (push) Has been cancelled
urchin tests / all test suites, all shells (push) Has been cancelled
Tests: `nvm install-latest-npm` / nvm install-latest-npm (push) Has been cancelled
Tests: linting / all linting (push) Has been cancelled
Tests: fast / all fast tests (push) Has been cancelled
Tests: installation_iojs / all installation_iojs tests (push) Has been cancelled
Tests: installation_node / all installation_node tests (push) Has been cancelled
Tests: xenial / all xenial tests (push) Has been cancelled
Tests on Windows: `nvm install` / tests, on windows (push) Has been cancelled
Tests on Windows: `nvm install` / MSYS nvm install (--default 12) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 12, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 18, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 21, Debian) (push) Has been cancelled
Tests: fast / fast (zsh, mawk) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 10, Ubuntu-18.04) (push) Has been cancelled
2026-06-29 17:33:31 -05:00
Jordan Harband 7a7908ffa1 [Dev Deps] update doctoc, semver 2026-06-29 16:43:55 -05:00
Jordan Harband ce15734300 [Fix] nvm install: migrate packages/set alias when target is already installed
When `nvm install <target>` found that `<target>` was already installed,
the post-`nvm use` steps
(`--reinstall-packages-from`, default packages, and `--alias`/`--default`)
were gated on `[ $EXIT_CODE -ne 0 ]`.
Since that branch is only entered when `nvm use` succeeded (EXIT_CODE == 0),
those conditions were always false, so the steps were silently skipped.

The fresh-install branch correctly uses `-eq 0`;
mirror that here so `--reinstall-packages-from` actually migrates global packages
(and the alias/default get set) when the target version already exists.

Includes a regression test covering the already-installed path.

Fixes #3858
2026-06-29 16:39:19 -05:00
Jordan Harband ee4fa818d2 [Docs] document nvm reinstall-packages as a standalone command
The standalone `nvm reinstall-packages <version>`
command can migrate global npm packages between already-installed versions,
but it was only mentioned in `nvm --help`, not in the README.
Add a section covering it.

Refs #3858
2026-06-29 14:51:15 -05:00
Jordan Harband a6ec739430 [Docs] document current and clarify .nvmrc fallback in help/README
Code scanning - action / CodeQL-Build (push) Has been cancelled
Tests: `nvm install-latest-npm` / matrix (push) Has been cancelled
Tests: linting / eclint (push) Has been cancelled
Tests: linting / dockerfile_lint (push) Has been cancelled
Tests: linting / doctoc (push) Has been cancelled
Tests: linting / test_naming (push) Has been cancelled
Tests: nvm install with set -e / matrix (push) Has been cancelled
Tests: release process / release (push) Has been cancelled
Tests: shellcheck / shellcheck_matrix (bash_completion, bash) (push) Has been cancelled
Tests: shellcheck / shellcheck_matrix (install.sh, bash) (push) Has been cancelled
Tests: shellcheck / shellcheck_matrix (nvm-exec, bash) (push) Has been cancelled
Tests: shellcheck / shellcheck_matrix (nvm.sh, bash) (push) Has been cancelled
Tests: shellcheck / shellcheck_matrix (nvm.sh, dash) (push) Has been cancelled
Tests: shellcheck / shellcheck_matrix (nvm.sh, ksh) (push) Has been cancelled
Tests: shellcheck / shellcheck_matrix (nvm.sh, sh) (push) Has been cancelled
Tests: fast / fast (bash, gawk) (push) Has been cancelled
Tests: fast / fast (dash, gawk) (push) Has been cancelled
Tests: fast / fast (sh, gawk) (push) Has been cancelled
Tests: fast / fast (zsh, gawk) (push) Has been cancelled
Tests: fast / fast (bash, mawk) (push) Has been cancelled
Tests: fast / fast (dash, mawk) (push) Has been cancelled
Tests: fast / fast (sh, mawk) (push) Has been cancelled
Tests: fast / fast (zsh, mawk) (push) Has been cancelled
Tests: installation_iojs / installation_iojs without curl (dash) (push) Has been cancelled
Tests: installation_iojs / installation_iojs without curl (zsh) (push) Has been cancelled
Tests: installation_node / installation_node (bash) (push) Has been cancelled
Tests: installation_node / installation_node (bash, without curl) (push) Has been cancelled
Tests: installation_node / installation_node (dash) (push) Has been cancelled
Tests: installation_node / installation_node (dash, without curl) (push) Has been cancelled
Tests: installation_node / installation_node (sh) (push) Has been cancelled
Tests: installation_node / installation_node (sh, without curl) (push) Has been cancelled
Tests: installation_node / installation_node (zsh) (push) Has been cancelled
Tests: installation_node / installation_node (zsh, without curl) (push) Has been cancelled
Tests: xenial / xenial (bash) (push) Has been cancelled
Tests: xenial / xenial (dash) (push) Has been cancelled
Tests: xenial / xenial (sh) (push) Has been cancelled
Tests: xenial / xenial (zsh) (push) Has been cancelled
urchin tests / tests (bash, install_script) (push) Has been cancelled
urchin tests / tests (bash, installation_iojs) (push) Has been cancelled
urchin tests / tests (bash, slow) (push) Has been cancelled
urchin tests / tests (bash, sourcing) (push) Has been cancelled
urchin tests / tests (dash, installation_iojs) (push) Has been cancelled
urchin tests / tests (dash, slow) (push) Has been cancelled
urchin tests / tests (dash, sourcing) (push) Has been cancelled
urchin tests / tests (sh, installation_iojs) (push) Has been cancelled
urchin tests / tests (sh, slow) (push) Has been cancelled
urchin tests / tests (sh, sourcing) (push) Has been cancelled
urchin tests / tests (zsh, slow) (push) Has been cancelled
urchin tests / tests (zsh, sourcing) (push) Has been cancelled
update readme TOC / update readme TOC (push) Has been cancelled
Tests on Windows: `nvm install` / MSYS fail prefix nvm install (push) Has been cancelled
Tests on Windows: `nvm install` / MSYS nvm install (--lts) (push) Has been cancelled
Tests on Windows: `nvm install` / MSYS nvm install (--no-progress 10) (push) Has been cancelled
Tests on Windows: `nvm install` / Cygwin nvm install (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 10, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 10, Ubuntu-18.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 10, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 12, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 12, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 14, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 14, Ubuntu-18.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 14, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 16, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 16, Ubuntu-18.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 16, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 18, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 18, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 21, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 21, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 10, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 10, Ubuntu-18.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 10, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 12, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 12, Ubuntu-18.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 12, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 14, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 14, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 16, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 16, Ubuntu-18.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 16, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 18, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 18, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 21, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 21, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, --lts, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 10, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 11, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 14, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 16, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 18, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 21, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, --lts, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 10, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 11, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 12, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 14, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 16, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 18, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 21, Alpine) (push) Has been cancelled
Tests: `nvm install-latest-npm` / nvm install-latest-npm (push) Has been cancelled
Tests: linting / all linting (push) Has been cancelled
Tests: nvm install with set -e / test (push) Has been cancelled
Tests: nvm install with set -e / finisher (push) Has been cancelled
Tests: shellcheck / shellcheck (push) Has been cancelled
Tests: fast / all fast tests (push) Has been cancelled
Tests: installation_iojs / all installation_iojs tests (push) Has been cancelled
Tests: installation_node / all installation_node tests (push) Has been cancelled
Tests: xenial / all xenial tests (push) Has been cancelled
urchin tests / all test suites, all shells (push) Has been cancelled
Tests on Windows: `nvm install` / tests, on windows (push) Has been cancelled
Tests: installation_iojs / installation_iojs without curl (bash) (push) Has been cancelled
Tests: installation_iojs / installation_iojs without curl (sh) (push) Has been cancelled
urchin tests / tests (zsh, installation_iojs) (push) Has been cancelled
Tests on Windows: `nvm install` / MSYS nvm install (--default 12) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 12, Ubuntu-18.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 14, Ubuntu-18.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 12, Alpine) (push) Has been cancelled
- Help text for `nvm install`/`use`/`exec`/`run`/`which` now ends with
  "Uses .nvmrc if version is omitted; otherwise errors."
  so it's clear that omitting the version is not a free fallback.
- Help signatures for `use`/`exec`/`run` now show `[current | <version>]`
  to mirror `nvm which` and document that `current` is accepted.
- `nvm current` description now spells out that it resolves via `$PATH`
  and is not affected by `.nvmrc`.
- README: add `current` to the list of special aliases, with the same caveat.
  The `.nvmrc` section now states that `nvm use`/`install`/`which`
  exit with status 127 when neither a version nor an `.nvmrc` resolves,
  notes the (current) `exec`/`run` fallback as undefined behavior,
  and points readers at `current` for the explicit "active node" use case.

Refs #3755
2026-06-10 15:16:24 -07:00
Jordan Harband 718e880890 [Fix] focused error on missing/invalid args for several subcommands
Previously a number of subcommands dumped the entire `nvm --help`
output (~100 lines) when arguments were missing or invalid,
drowning the real error.
Replace each dump with a short,
command-specific usage block that names the expected syntax and points to `nvm --help` for full help.
The exit code (127) is unchanged.

Affected subcommands:
- `nvm install` (no version + no .nvmrc)
- `nvm use`     (version unresolvable)
- `nvm run`     (no version + no .nvmrc)
- `nvm which`   (no version + no .nvmrc)
- `nvm cache`   (unknown subcommand)
- `nvm uninstall`         (wrong arg count)
- `nvm unalias`           (wrong arg count)
- `nvm install-latest-npm` (wrong arg count)
- `nvm reinstall-packages` / `nvm copy-packages` (wrong arg count)

The catch-all unknown-subcommand handler still dumps full help, since
in that case the user has no narrower context to be reminded about.

Refs #3755
2026-06-10 15:16:23 -07:00
Jordan Harband ed4dbdfdd5 [Fix] nvm_rc_version: clarify error when no version and no .nvmrc
Previously the message read "No .nvmrc file found",
which obscured the fact that the user also did not pass a version.
The new wording names both halves of the actual problem.

Refs #3755
2026-06-10 15:16:23 -07:00
Jordan Harband a9933f77a6 [Fix] nvm exec/nvm run: warn when no version and no .nvmrc
Currently these commands silently fall back to the active node version when neither a version argument nor an `.nvmrc` resolves,
making them invisibly dependent on shell state and impossible to script predictably (see #3755).

Print a stderr deprecation warning in this case (suppressed by `--silent`) and continue with the active node version,
so existing callers keep working.
The follow-up change will turn this into a hard error;
pass `current` explicitly (e.g. `nvm exec current node ...`) to silence the warning and lock in the new behavior now.

Refs #3755
2026-06-10 15:16:23 -07:00
Jordan Harband 7079a5d61c [actions] nodejs.org PR: sync the fork before branching, and surface create-ref errors
Code scanning - action / CodeQL-Build (push) Has been cancelled
Tests: linting / eclint (push) Has been cancelled
Tests: linting / dockerfile_lint (push) Has been cancelled
Tests: linting / doctoc (push) Has been cancelled
Tests: linting / test_naming (push) Has been cancelled
Tests: installation_node / installation_node (bash) (push) Has been cancelled
Tests: installation_node / installation_node (bash, without curl) (push) Has been cancelled
Tests: installation_node / installation_node (dash) (push) Has been cancelled
Tests: installation_node / installation_node (dash, without curl) (push) Has been cancelled
Tests: installation_node / installation_node (sh) (push) Has been cancelled
Tests: installation_node / installation_node (sh, without curl) (push) Has been cancelled
Tests: installation_node / installation_node (zsh) (push) Has been cancelled
Tests: installation_node / installation_node (zsh, without curl) (push) Has been cancelled
Tests: xenial / xenial (bash) (push) Has been cancelled
Tests: xenial / xenial (dash) (push) Has been cancelled
Tests: xenial / xenial (sh) (push) Has been cancelled
Tests: xenial / xenial (zsh) (push) Has been cancelled
update readme TOC / update readme TOC (push) Has been cancelled
Tests: `nvm install-latest-npm` / matrix (push) Has been cancelled
Tests: fast / fast (bash, gawk) (push) Has been cancelled
Tests: fast / fast (dash, gawk) (push) Has been cancelled
Tests: shellcheck / shellcheck_matrix (bash_completion, bash) (push) Has been cancelled
Tests: shellcheck / shellcheck_matrix (nvm-exec, bash) (push) Has been cancelled
Tests: shellcheck / shellcheck_matrix (nvm.sh, bash) (push) Has been cancelled
Tests: shellcheck / shellcheck_matrix (nvm.sh, dash) (push) Has been cancelled
Tests: fast / fast (zsh, gawk) (push) Has been cancelled
Tests: fast / fast (bash, mawk) (push) Has been cancelled
Tests: installation_iojs / installation_iojs without curl (sh) (push) Has been cancelled
urchin tests / tests (bash, sourcing) (push) Has been cancelled
urchin tests / tests (dash, installation_iojs) (push) Has been cancelled
urchin tests / tests (dash, slow) (push) Has been cancelled
Tests: release process / release (push) Has been cancelled
Tests: shellcheck / shellcheck_matrix (install.sh, bash) (push) Has been cancelled
Tests: shellcheck / shellcheck_matrix (nvm.sh, ksh) (push) Has been cancelled
Tests: shellcheck / shellcheck_matrix (nvm.sh, sh) (push) Has been cancelled
Tests: fast / fast (sh, gawk) (push) Has been cancelled
Tests: fast / fast (dash, mawk) (push) Has been cancelled
Tests: fast / fast (sh, mawk) (push) Has been cancelled
Tests: fast / fast (zsh, mawk) (push) Has been cancelled
Tests: installation_iojs / installation_iojs without curl (dash) (push) Has been cancelled
Tests: installation_iojs / installation_iojs without curl (zsh) (push) Has been cancelled
urchin tests / tests (bash, install_script) (push) Has been cancelled
urchin tests / tests (bash, installation_iojs) (push) Has been cancelled
urchin tests / tests (bash, slow) (push) Has been cancelled
urchin tests / tests (dash, sourcing) (push) Has been cancelled
urchin tests / tests (sh, installation_iojs) (push) Has been cancelled
urchin tests / tests (sh, slow) (push) Has been cancelled
urchin tests / tests (sh, sourcing) (push) Has been cancelled
urchin tests / tests (zsh, installation_iojs) (push) Has been cancelled
urchin tests / tests (zsh, slow) (push) Has been cancelled
urchin tests / tests (zsh, sourcing) (push) Has been cancelled
Tests on Windows: `nvm install` / MSYS fail prefix nvm install (push) Has been cancelled
Tests on Windows: `nvm install` / MSYS nvm install (--default 12) (push) Has been cancelled
Tests on Windows: `nvm install` / MSYS nvm install (--lts) (push) Has been cancelled
Tests on Windows: `nvm install` / MSYS nvm install (--no-progress 10) (push) Has been cancelled
Tests on Windows: `nvm install` / Cygwin nvm install (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 10, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 10, Ubuntu-18.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 10, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 12, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 14, Ubuntu-18.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 14, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 16, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 16, Ubuntu-18.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 21, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 21, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 10, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 10, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 12, Ubuntu-18.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 14, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, --lts, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 11, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 14, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 16, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 18, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 18, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 10, Ubuntu-18.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 12, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 12, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 14, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 14, Ubuntu-18.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 16, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 16, Ubuntu-18.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 16, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 18, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 18, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 21, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 21, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 10, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 12, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 14, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 16, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 18, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 21, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, --lts, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 10, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 11, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 12, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 14, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 16, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 21, Alpine) (push) Has been cancelled
Tests: linting / all linting (push) Has been cancelled
Tests: installation_node / all installation_node tests (push) Has been cancelled
Tests: xenial / all xenial tests (push) Has been cancelled
Tests: `nvm install-latest-npm` / nvm install-latest-npm (push) Has been cancelled
Tests: nvm install with set -e / test (push) Has been cancelled
Tests: nvm install with set -e / finisher (push) Has been cancelled
Tests: shellcheck / shellcheck (push) Has been cancelled
Tests: fast / all fast tests (push) Has been cancelled
Tests: installation_iojs / all installation_iojs tests (push) Has been cancelled
urchin tests / all test suites, all shells (push) Has been cancelled
Tests on Windows: `nvm install` / tests, on windows (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 18, Alpine) (push) Has been cancelled
Tests: nvm install with set -e / matrix (push) Has been cancelled
Tests: installation_iojs / installation_iojs without curl (bash) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 12, Ubuntu-18.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 12, Ubuntu-20.04) (push) Has been cancelled
2026-06-04 14:52:41 -07:00
Jordan Harband 306f04a90a [actions] nodejs.org PR: fix force boolean and grab the latest tag on dispatch
Code scanning - action / CodeQL-Build (push) Has been cancelled
Tests: `nvm install-latest-npm` / nvm install-latest-npm (push) Has been cancelled
Tests: `nvm install-latest-npm` / matrix (push) Has been cancelled
Tests: linting / eclint (push) Has been cancelled
Tests: linting / dockerfile_lint (push) Has been cancelled
Tests: linting / doctoc (push) Has been cancelled
Tests: linting / test_naming (push) Has been cancelled
Tests: linting / all linting (push) Has been cancelled
Tests: nvm install with set -e / matrix (push) Has been cancelled
Tests: nvm install with set -e / test (push) Has been cancelled
Tests: nvm install with set -e / finisher (push) Has been cancelled
Tests: release process / release (push) Has been cancelled
Tests: shellcheck / shellcheck_matrix (bash_completion, bash) (push) Has been cancelled
Tests: shellcheck / shellcheck_matrix (install.sh, bash) (push) Has been cancelled
Tests: shellcheck / shellcheck_matrix (nvm-exec, bash) (push) Has been cancelled
Tests: shellcheck / shellcheck_matrix (nvm.sh, bash) (push) Has been cancelled
Tests: shellcheck / shellcheck_matrix (nvm.sh, dash) (push) Has been cancelled
Tests: shellcheck / shellcheck_matrix (nvm.sh, ksh) (push) Has been cancelled
Tests: shellcheck / shellcheck_matrix (nvm.sh, sh) (push) Has been cancelled
Tests: shellcheck / shellcheck (push) Has been cancelled
Tests: fast / all fast tests (push) Has been cancelled
Tests: fast / fast (bash, gawk) (push) Has been cancelled
Tests: fast / fast (dash, gawk) (push) Has been cancelled
Tests: fast / fast (sh, gawk) (push) Has been cancelled
Tests: fast / fast (zsh, gawk) (push) Has been cancelled
Tests: fast / fast (dash, mawk) (push) Has been cancelled
Tests: fast / fast (sh, mawk) (push) Has been cancelled
Tests: fast / fast (zsh, mawk) (push) Has been cancelled
Tests: installation_iojs / installation_iojs without curl (bash) (push) Has been cancelled
Tests: installation_iojs / installation_iojs without curl (dash) (push) Has been cancelled
Tests: installation_iojs / installation_iojs without curl (sh) (push) Has been cancelled
Tests: installation_iojs / installation_iojs without curl (zsh) (push) Has been cancelled
Tests: installation_iojs / all installation_iojs tests (push) Has been cancelled
Tests: installation_node / installation_node (dash) (push) Has been cancelled
Tests: installation_node / installation_node (dash, without curl) (push) Has been cancelled
Tests: installation_node / installation_node (sh) (push) Has been cancelled
Tests: installation_node / installation_node (sh, without curl) (push) Has been cancelled
Tests: installation_node / installation_node (zsh) (push) Has been cancelled
Tests: installation_node / installation_node (zsh, without curl) (push) Has been cancelled
Tests: installation_node / all installation_node tests (push) Has been cancelled
Tests: installation_node / installation_node (bash) (push) Has been cancelled
Tests: installation_node / installation_node (bash, without curl) (push) Has been cancelled
Tests: xenial / xenial (bash) (push) Has been cancelled
Tests: xenial / xenial (dash) (push) Has been cancelled
Tests: xenial / xenial (sh) (push) Has been cancelled
Tests: xenial / xenial (zsh) (push) Has been cancelled
Tests: xenial / all xenial tests (push) Has been cancelled
urchin tests / tests (bash, install_script) (push) Has been cancelled
urchin tests / all test suites, all shells (push) Has been cancelled
urchin tests / tests (bash, installation_iojs) (push) Has been cancelled
urchin tests / tests (bash, slow) (push) Has been cancelled
urchin tests / tests (bash, sourcing) (push) Has been cancelled
urchin tests / tests (dash, slow) (push) Has been cancelled
urchin tests / tests (dash, sourcing) (push) Has been cancelled
urchin tests / tests (sh, installation_iojs) (push) Has been cancelled
urchin tests / tests (sh, slow) (push) Has been cancelled
urchin tests / tests (sh, sourcing) (push) Has been cancelled
urchin tests / tests (zsh, installation_iojs) (push) Has been cancelled
urchin tests / tests (zsh, slow) (push) Has been cancelled
urchin tests / tests (zsh, sourcing) (push) Has been cancelled
update readme TOC / update readme TOC (push) Has been cancelled
Tests on Windows: `nvm install` / MSYS fail prefix nvm install (push) Has been cancelled
Tests on Windows: `nvm install` / MSYS nvm install (--default 12) (push) Has been cancelled
Tests on Windows: `nvm install` / MSYS nvm install (--lts) (push) Has been cancelled
Tests on Windows: `nvm install` / MSYS nvm install (--no-progress 10) (push) Has been cancelled
Tests on Windows: `nvm install` / Cygwin nvm install (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 10, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 10, Ubuntu-18.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 10, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 12, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 12, Ubuntu-18.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 12, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 14, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 14, Ubuntu-18.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 14, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 16, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 16, Ubuntu-18.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 16, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 18, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 18, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 21, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 21, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 10, Ubuntu-18.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 10, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 12, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 12, Ubuntu-18.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 12, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 14, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 14, Ubuntu-18.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 14, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 16, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 16, Ubuntu-18.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 16, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 18, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 18, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 21, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 21, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, --lts, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 10, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 11, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 12, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 14, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 16, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 18, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 21, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, --lts, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 10, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 11, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 21, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 12, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 14, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 16, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 18, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / tests, on windows (push) Has been cancelled
Tests: fast / fast (bash, mawk) (push) Has been cancelled
urchin tests / tests (dash, installation_iojs) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 10, Debian) (push) Has been cancelled
The branch-reset step sent `force` as a string via `gh api -f "force=true"`,
which the Git refs API rejects ("not a boolean", HTTP 422), failing the release run.
Use `-F` so it is sent as a boolean.

Also resolve the version from the latest `vX.Y.Z` tag
(via the tags API) rather than `releases/latest`,
so a manual `workflow_dispatch` with no input works even before the GitHub release object for a freshly pushed tag is published.
2026-06-04 09:54:01 -07:00
Jordan Harband 77fca77ddd [actions] fall back to the canonical nvmrc submodule when a fork lacks its own
Upstream's `.gitmodules` uses a relative submodule url (`../nvmrc.git`),
which resolves against the superproject's origin:
on a fork without its own `nvmrc` fork that is `<owner>/nvmrc`,
which 404s and fails `actions/checkout` with `submodules: true`.
Keep `submodules: true` (so a fork's own `nvmrc` is used when present),
but mark checkout `continue-on-error` and, only when it failed,
re-point the submodule at `nvm-sh/nvmrc` and update.
2026-06-04 09:22:04 -07:00
Jordan Harband 1889911f08 v0.40.5 2026-06-04 09:33:05 -07:00
Jordan Harband 70fb4ede6b [Fix] nvm_download_artifact: reject version strings with disallowed characters
The mirror-supplied (untrusted) version flows into download URLs,
filesystem paths, and the checksum awk match.
Reject any version outside the node/io.js grammar
(`[0-9A-Za-z._+-]`) before it is used.
A blocklist of metacharacters is used rather than a strict semver allowlist so RCs, nightlies, v8-canary, and io.js versions still install.

Completes the remediation of GHSA-3c52-35h2-gfmm.
2026-06-03 13:09:07 -07:00
Jordan Harband 90bb88748b [Fix] nvm_get_checksum: pass the tarball name to awk as data, not program text
The awk program string-interpolated the slug
(which embeds the untrusted, mirror-supplied version)
into its source, so a crafted version such as
`v1"==$2){system("touch${IFS}/tmp/x")}#`
was executed by awk's `system()`.
Pass the value via `-v tarball=...` so awk treats it as data and never as code.

See GHSA-3c52-35h2-gfmm
(a second injection sink fed by the same untrusted version field that `nvm_download`'s eval was; the source-install path reaches this during a normal `nvm install <version>`).
2026-06-03 13:11:26 -07:00
Jordan Harband 6d870d182c [Fix] nvm_download: avoid eval so mirror-supplied version strings can't inject commands
`nvm_download` built a curl/wget command string and ran it with `eval`.
The download URLs embed the version string taken from the mirror's `index.tab`,
which is untrusted.
Wrapping each argument in double quotes inside the `eval` does not prevent command substitution,
so a version field such as `v1$(touch /tmp/proof)` was executed by the shell.
This bypassed the earlier quoting hardening in 0ce8f5a.

Pass every argument as a literal argv element instead of constructing a string for `eval`,
on both the curl and wget paths,
so URL arguments are never re-parsed by the shell.
The wget flag translation is now done per-argument with a POSIX
`set --` loop rather than `sed` over the joined string.
The auth header is sanitized and added once,
before invoking the downloader.
2026-06-02 17:41:44 -07:00
Jordan Harband d264b796a3 [Fix] nvm_download: send a well-formed Authorization header on the wget path
The wget path passed `NVM_AUTH_HEADER` as the raw header line
(e.g. `--header "Bearer secret-token"`),
omitting the `Authorization:` header name that the curl path includes.
Per the documented usage
(`NVM_AUTH_HEADER="Bearer secret-token"`) the value is the credential,
so wget was sending a malformed header.
Prefix it with `Authorization: ` to match the curl path.
2026-06-02 17:40:50 -07:00
Jordan Harband 84079dbff3 [Tests] install_nvm_from_git: stop git background gc/maintenance racing with cleanup
The test's `rm -rf "$NVM_DIR"` intermittently failed with
`rm: cannot remove...: Directory not empty`
and aborted under `set -e`.
Cause: after the clone/fetch, git can spawn a detached background gc/maintenance process that keeps writing into the clone dir while `rm -rf` runs (a concurrent writer makes the final rmdir fail).
It is not egress- or version-related
(it reproduces with all endpoints allowed),
and it is environment-timing dependent
(recently became consistent on the GitHub runners).

Disable git's background work for the test (gc.autoDetach / maintenance.auto)
so all git operations finish synchronously, and retry the rm once as a safety net.
2026-06-03 20:12:26 -07:00
Jordan Harband 61c9ff7371 [Tests] install_nvm_from_git: fix malformed test command (missing space before ])
`[ "${head_ref}" != "${avoid_ref}"]` is missing the space before the closing bracket,
so the shell prints `[: missing ']'` and the avoid_ref assertion never actually runs
(it is inside an `if` condition, so the error was non-fatal and silently disabled the check)
2026-06-03 14:53:48 -07:00
Jordan Harband 16f6ddc3d5 [actions] set per-job permissions in the nvm install workflow
CodeQL (actions/missing-workflow-permissions)
flagged the matrix, test, and finisher jobs of nvm-install-test.yml for not declaring permissions.
Every other test workflow already sets least-privilege permissions per job; add them here to match:
`contents: read` for the matrix and test jobs, `contents: none` for the no-op finisher.
2026-06-03 14:09:02 -07:00
Jordan Harband c4d9239cbb [actions] allow DockerHub's CloudFront CDN so image pulls aren't blocked
harden-runner runs with `egress-policy: block`, and the allow-list only included
`production.cloudflare.docker.com`. DockerHub serves image blobs from either its
Cloudflare or its CloudFront CDN; when a pull was routed to CloudFront
(`production.cloudfront.docker.com`) the connection was dropped, causing
`error pulling image configuration: ... connect: connection refused` and exit
125 in the xenial, installation_node, and fast (httpbin) suites. Allow both CDNs.
2026-06-03 13:29:38 -07:00
Jordan Harband dd13968c1e [Tests] reduce CI flakiness from transient Docker registry failures
Container-based suites and the `nvm_download` httpbin check hard-fail whenever DockerHub is briefly unreachable
(observed: `dial tcp ...:443: connect: connection refused` while pulling images),
even though the change under test is fine.
This is unrelated to any test logic.

- tests-xenial / tests-installation-node: retry the `docker pull` up to 5 times before `docker run`, mirroring the existing apt-get retry
- `nvm_download` test: retry the httpbin pull and skip the auth-header checks (rather than fail) when the image cannot be pulled or run, and make cleanup tolerant of a missing container.
2026-06-03 13:12:31 -07:00
25 changed files with 758 additions and 115 deletions
+9 -5
View File
@@ -7,7 +7,7 @@ on:
workflow_dispatch:
inputs:
version:
description: 'nvm version tag (e.g., v0.40.4). Defaults to latest release.'
description: 'nvm version tag (e.g., v0.40.4). Defaults to the latest version tag.'
required: false
default: ''
@@ -18,7 +18,7 @@ jobs:
update-nodejs-org:
if: github.repository == 'nvm-sh/nvm' && github.actor == 'ljharb'
permissions:
contents: none
contents: read # for the "Extract and validate version" step's `gh api .../tags` call via the default github.token
name: 'Create PR to nodejs/nodejs.org'
runs-on: ubuntu-latest
steps:
@@ -41,7 +41,8 @@ jobs:
elif [ "${GITHUB_REF_TYPE}" = "tag" ]; then
TAG="${GITHUB_REF#refs/tags/}"
else
TAG="$(gh api "repos/${GITHUB_REPOSITORY}/releases/latest" --jq '.tag_name')"
TAG="$(gh api --paginate "repos/${GITHUB_REPOSITORY}/tags" --jq '.[].name' \
| grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' | sort -V | tail -n 1)"
fi
if ! printf '%s\n' "${TAG}" | grep -qE '^v[0-9]+\.[0-9]+\.[0-9]+$'; then
@@ -65,16 +66,19 @@ jobs:
FORK_OWNER="$(gh api user --jq '.login')"
DEFAULT_BRANCH="$(gh api repos/nodejs/nodejs.org --jq '.default_branch')"
gh repo sync "${FORK_OWNER}/nodejs.org" --branch "${DEFAULT_BRANCH}" || true
UPSTREAM_SHA="$(gh api "repos/nodejs/nodejs.org/git/ref/heads/${DEFAULT_BRANCH}" --jq '.object.sha')"
# Create or reset branch on fork to upstream HEAD
if ! gh api "repos/${FORK_OWNER}/nodejs.org/git/refs" \
-f "ref=refs/heads/${BRANCH}" \
-f "sha=${UPSTREAM_SHA}" > /dev/null 2>&1; then
-f "sha=${UPSTREAM_SHA}" > /dev/null; then
gh api "repos/${FORK_OWNER}/nodejs.org/git/refs/heads/${BRANCH}" \
-X PATCH \
-f "sha=${UPSTREAM_SHA}" \
-f "force=true" > /dev/null
-F "force=true" > /dev/null
fi
printf 'fork_owner=%s\n' "${FORK_OWNER}" >> "${GITHUB_OUTPUT}"
+6
View File
@@ -15,6 +15,8 @@ permissions:
jobs:
matrix:
permissions:
contents: read
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.matrix.outputs.matrix }}
@@ -43,6 +45,8 @@ jobs:
fi
test:
permissions:
contents: read
needs: [matrix]
runs-on: ubuntu-latest
continue-on-error: ${{ matrix.ref == 'v0.40.0' }} # https://github.com/nvm-sh/nvm/issues/3405
@@ -101,6 +105,8 @@ jobs:
fi
finisher:
permissions:
contents: none
runs-on: ubuntu-latest
needs: [test]
steps:
+6 -10
View File
@@ -2,16 +2,12 @@ name: Automatic Rebase
on: [pull_request_target]
permissions: read-all
permissions:
contents: write # for ljharb/rebase to push code to rebase
pull-requests: read # for ljharb/rebase to get info about PR
jobs:
_:
name: "Automatic Rebase"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: ljharb/rebase@master
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
uses: ljharb/actions/.github/workflows/rebase.yml@main
secrets:
token: ${{ secrets.GITHUB_TOKEN }}
+5 -1
View File
@@ -2,10 +2,14 @@ name: Require “Allow Edits”
on: [pull_request_target]
permissions: read-all
permissions:
contents: read
jobs:
_:
permissions:
pull-requests: read # for ljharb/require-allow-edits to check 'allow edits' on PR
name: "Require “Allow Edits”"
runs-on: ubuntu-latest
+10
View File
@@ -45,9 +45,19 @@ jobs:
registry-1.docker.io:443
auth.docker.io:443
production.cloudflare.docker.com:443
production.cloudfront.docker.com:443
- uses: actions/checkout@v6
id: checkout
continue-on-error: true
with:
submodules: true
- name: 'nvmrc submodule fallback (forks without their own nvmrc)'
if: steps.checkout.outcome == 'failure'
shell: bash
run: |
git submodule set-url test/fixtures/nvmrc https://github.com/nvm-sh/nvmrc.git
git submodule sync --recursive
git submodule update --init --recursive
- name: Install zsh, additional shells, and awk variant
run: |
sudo apt-get update
@@ -39,8 +39,17 @@ jobs:
azure.archive.ubuntu.com:80
packages.microsoft.com:443
- uses: actions/checkout@v6
id: checkout
continue-on-error: true
with:
submodules: true
- name: 'nvmrc submodule fallback (forks without their own nvmrc)'
if: steps.checkout.outcome == 'failure'
shell: bash
run: |
git submodule set-url test/fixtures/nvmrc https://github.com/nvm-sh/nvmrc.git
git submodule sync --recursive
git submodule update --init --recursive
- name: Install zsh and additional shells
run: |
sudo apt-get update
@@ -41,11 +41,21 @@ jobs:
archive.ubuntu.com:80
security.ubuntu.com:80
production.cloudflare.docker.com:443
production.cloudfront.docker.com:443
registry-1.docker.io:443
auth.docker.io:443
- uses: actions/checkout@v6
id: checkout
continue-on-error: true
with:
submodules: true
- name: 'nvmrc submodule fallback (forks without their own nvmrc)'
if: steps.checkout.outcome == 'failure'
shell: bash
run: |
git submodule set-url test/fixtures/nvmrc https://github.com/nvm-sh/nvmrc.git
git submodule sync --recursive
git submodule update --init --recursive
- uses: ljharb/actions/node/install@main
name: 'npm install && version checks'
with:
@@ -55,6 +65,12 @@ jobs:
- run: npx which urchin
- name: Run installation_node tests in container
run: |
# Retry the image pull to tolerate transient Docker registry failures
for i in 1 2 3 4 5; do
docker pull ubuntu:16.04 && break
echo "docker pull failed, attempt $i/5"
sleep $((i * 5))
done
docker run --rm \
-v "${{ github.workspace }}:/workspace" \
-w /workspace \
+16
View File
@@ -38,11 +38,21 @@ jobs:
archive.ubuntu.com:80
security.ubuntu.com:80
production.cloudflare.docker.com:443
production.cloudfront.docker.com:443
registry-1.docker.io:443
auth.docker.io:443
- uses: actions/checkout@v6
id: checkout
continue-on-error: true
with:
submodules: true
- name: 'nvmrc submodule fallback (forks without their own nvmrc)'
if: steps.checkout.outcome == 'failure'
shell: bash
run: |
git submodule set-url test/fixtures/nvmrc https://github.com/nvm-sh/nvmrc.git
git submodule sync --recursive
git submodule update --init --recursive
- uses: ljharb/actions/node/install@main
name: 'npm install && version checks'
with:
@@ -52,6 +62,12 @@ jobs:
- run: npx which urchin
- name: Run xenial tests in container
run: |
# Retry the image pull to tolerate transient Docker registry failures
for i in 1 2 3 4 5; do
docker pull ubuntu:16.04 && break
echo "docker pull failed, attempt $i/5"
sleep $((i * 5))
done
docker run --rm \
-v "${{ github.workspace }}:/workspace" \
-w /workspace \
+1 -1
View File
@@ -8,7 +8,7 @@ permissions:
jobs:
tests:
permissions:
contents: write
contents: read # for actions/checkout@v6
name: "tests"
runs-on: ubuntu-latest
+4
View File
@@ -94,6 +94,8 @@ jobs:
bash.exe "%USERPROFILE%\setup.sh"
wsl_matrix:
permissions:
contents: none
continue-on-error: true
name: 'WSL nvm install'
defaults:
@@ -187,6 +189,8 @@ jobs:
node -v
wsl_matrix_unofficial:
permissions:
contents: none
continue-on-error: true
name: 'WSL nvm install'
defaults:
+30 -17
View File
@@ -6,7 +6,7 @@
</a>
# Node Version Manager [![Tests](https://github.com/nvm-sh/nvm/actions/workflows/tests-fast.yml/badge.svg?branch=master)][3] [![nvm version](https://img.shields.io/badge/version-v0.40.4-yellow.svg)][4] [![CII Best Practices](https://bestpractices.dev/projects/684/badge)](https://bestpractices.dev/projects/684)
# Node Version Manager [![Tests](https://github.com/nvm-sh/nvm/actions/workflows/tests-fast.yml/badge.svg?branch=master)][3] [![nvm version](https://img.shields.io/badge/version-v0.40.5-yellow.svg)][4] [![CII Best Practices](https://bestpractices.dev/projects/684/badge)](https://bestpractices.dev/projects/684)
<!-- To update this table of contents, ensure you have run `npm install` then `npm run doctoc` -->
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
@@ -31,6 +31,7 @@
- [Usage](#usage)
- [Long-term Support](#long-term-support)
- [Migrating Global Packages While Installing](#migrating-global-packages-while-installing)
- [Migrating Global Packages Between Installed Versions](#migrating-global-packages-between-installed-versions)
- [Offline Install](#offline-install)
- [Default Global Packages From File While Installing](#default-global-packages-from-file-while-installing)
- [io.js](#iojs)
@@ -105,10 +106,10 @@ nvm is a version manager for [node.js](https://nodejs.org/en/), designed to be i
To **install** or **update** nvm, you should run the [install script][2]. To do that, you may either download and run the script manually, or use the following cURL or Wget command:
```sh
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.4/install.sh | bash
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.5/install.sh | bash
```
```sh
wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.4/install.sh | bash
wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.5/install.sh | bash
```
Running either of the above commands downloads a script and runs it. The script clones the nvm repository to `~/.nvm`, and attempts to add the source lines from the snippet below to the correct profile file (`~/.bashrc`, `~/.bash_profile`, `~/.zshrc`, or `~/.profile`). If you find the install script is updating the wrong profile file, set the `$PROFILE` env var to the profile file’s path, and then rerun the installation script.
@@ -135,7 +136,7 @@ Eg: `curl ... | NVM_DIR="path/to/nvm"`. Ensure that the `NVM_DIR` does not conta
- The installer can use `git`, `curl`, or `wget` to download `nvm`, whichever is available.
- You can instruct the installer to not edit your shell config (for example if you already get completions via a [zsh nvm plugin](https://github.com/ohmyzsh/ohmyzsh/tree/master/plugins/nvm)) by setting `PROFILE=/dev/null` before running the `install.sh` script. Here's an example one-line command to do that: `PROFILE=/dev/null bash -c 'curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.4/install.sh | bash'`
- You can instruct the installer to not edit your shell config (for example if you already get completions via a [zsh nvm plugin](https://github.com/ohmyzsh/ohmyzsh/tree/master/plugins/nvm)) by setting `PROFILE=/dev/null` before running the `install.sh` script. Here's an example one-line command to do that: `PROFILE=/dev/null bash -c 'curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.5/install.sh | bash'`
#### Installing in Docker
@@ -151,7 +152,7 @@ RUN touch "${BASH_ENV}"
RUN echo '. "${BASH_ENV}"' >> ~/.bashrc
# Download and install nvm
RUN curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.4/install.sh | PROFILE="${BASH_ENV}" bash
RUN curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.5/install.sh | PROFILE="${BASH_ENV}" bash
RUN echo node > .nvmrc
RUN nvm install
```
@@ -169,7 +170,7 @@ ARG NODE_VERSION=20
RUN apt update && apt install curl -y
# install nvm
RUN curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.4/install.sh | bash
RUN curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.5/install.sh | bash
# set env
ENV NVM_DIR=/root/.nvm
@@ -195,7 +196,7 @@ After creation of the image you can start container interactively and run comman
docker run --rm -it nvmimage
root@0a6b5a237c14:/# nvm -v
0.40.4
0.40.5
root@0a6b5a237c14:/# node -v
v19.9.0
@@ -258,7 +259,7 @@ You can use a task:
```yaml
- name: Install nvm
ansible.builtin.shell: >
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.4/install.sh | bash
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.5/install.sh | bash
args:
creates: "{{ ansible_env.HOME }}/.nvm/nvm.sh"
```
@@ -320,7 +321,7 @@ If you have `git` installed (requires git v1.7.10+):
1. clone this repo in the root of your user profile
- `cd ~/` from anywhere then `git clone https://github.com/nvm-sh/nvm.git .nvm`
1. `cd ~/.nvm` and check out the latest version with `git checkout v0.40.4`
1. `cd ~/.nvm` and check out the latest version with `git checkout v0.40.5`
1. activate `nvm` by sourcing it from your shell: `. ./nvm.sh`
Now add these lines to your `~/.bashrc`, `~/.profile`, or `~/.zshrc` file to have it automatically sourced upon login:
@@ -429,6 +430,7 @@ In place of a version pointer like "14.7" or "16.3" or "12.22.1", you can use th
- `iojs`: this installs the latest version of [`io.js`](https://iojs.org/en/)
- `stable`: this alias is deprecated, and only truly applies to `node` `v0.12` and earlier. Currently, this is an alias for `node`.
- `unstable`: this alias points to `node` `v0.11` - the last "unstable" node release, since post-1.0, all node versions are stable. (in SemVer, versions communicate breakage, not stability).
- `current`: the version currently active in this shell (i.e. what `node` resolves to via `$PATH`). It is **not** affected by `.nvmrc`. Useful when you want to refer to the active version explicitly &mdash; e.g. `nvm which current` always prints the path to the active `node`, regardless of whether an `.nvmrc` file is present.
### Long-term Support
@@ -482,6 +484,17 @@ nvm install-latest-npm
If you've already gotten an error to the effect of "npm does not support Node.js", you'll need to (1) revert to a previous node version (`nvm ls` & `nvm use <your latest _working_ version from the ls>`), (2) delete the newly created node version (`nvm uninstall <your _broken_ version of node from the ls>`), then (3) rerun your `nvm install` with the `--latest-npm` flag.
### Migrating Global Packages Between Installed Versions
`--reinstall-packages-from` is tied to `nvm install`. To migrate global npm packages between versions you _already_ have installed, without (re)installing anything, `nvm use` the destination and run `nvm reinstall-packages` as a standalone command, pointing at the version you want to copy _from_:
```sh
nvm use 22.22.2
nvm reinstall-packages 22.20.0
```
This reinstalls all global packages from `22.20.0` into the currently-active version (`22.22.2`). As with `--reinstall-packages-from`, the npm version itself is not changed.
### Offline Install
@@ -645,7 +658,7 @@ NVM_AUTH_HEADER="Bearer secret-token" nvm install node
### .nvmrc
You can create a `.nvmrc` file containing a node version number (or any other string that `nvm` understands; see `nvm --help` for details) in the project root directory (or any parent directory).
Afterwards, `nvm use`, `nvm install`, `nvm exec`, `nvm run`, and `nvm which` will use the version specified in the `.nvmrc` file if no version is supplied on the command line.
Afterwards, `nvm use`, `nvm install`, and `nvm which` will use the version specified in the `.nvmrc` file if no version is supplied on the command line; if no `.nvmrc` is found either, they exit with status `127`. (`nvm exec` and `nvm run` follow the same `.nvmrc` lookup, but currently fall back to the active node if neither resolves &mdash; treat that fallback as undefined behavior; pass an explicit version if you need predictable scripting.) If you want the currently active version, pass `current` explicitly (e.g. `nvm which current`) &mdash; `current` is not affected by `.nvmrc`.
For example, to make nvm default to the latest 5.9 release, the latest LTS version, or the latest node version for the current directory:
@@ -945,13 +958,13 @@ If installing nvm on Alpine Linux *is* still what you want or need to do, you sh
### Alpine Linux 3.13+
```sh
apk add -U curl bash ca-certificates openssl ncurses coreutils python3 make gcc g++ libgcc linux-headers grep util-linux binutils findutils
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.4/install.sh | bash
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.5/install.sh | bash
```
### Alpine Linux 3.5 - 3.12
```sh
apk add -U curl bash ca-certificates openssl ncurses coreutils python2 make gcc g++ libgcc linux-headers grep util-linux binutils findutils
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.4/install.sh | bash
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.5/install.sh | bash
```
_Note: Alpine 3.5 can only install NodeJS versions up to v6.9.5, Alpine 3.6 can only install versions up to v6.10.3, Alpine 3.7 installs versions up to v8.9.3, Alpine 3.8 installs versions up to v8.14.0, Alpine 3.9 installs versions up to v10.19.0, Alpine 3.10 installs versions up to v10.24.1, Alpine 3.11 installs versions up to v12.22.6, Alpine 3.12 installs versions up to v12.22.12, Alpine 3.13 & 3.14 install versions up to v14.20.0, Alpine 3.15 & 3.16 install versions up to v16.16.0 (**These are all versions on the main branch**). Alpine 3.5 - 3.12 required the package `python2` to build NodeJS, as they are older versions to build. Alpine 3.13+ requires `python3` to successfully build newer NodeJS versions, but you can use `python2` with Alpine 3.13+ if you need to build versions of node supported in Alpine 3.5 - 3.15, you just need to specify what version of NodeJS you need to install in the package install script._
@@ -1054,9 +1067,9 @@ You have to make sure that the user directory name in `$HOME` and the user direc
To change the user directory and/or account name follow the instructions [here](https://support.apple.com/en-us/HT201548)
[1]: https://github.com/nvm-sh/nvm.git
[2]: https://github.com/nvm-sh/nvm/blob/v0.40.4/install.sh
[2]: https://github.com/nvm-sh/nvm/blob/v0.40.5/install.sh
[3]: https://github.com/nvm-sh/nvm/actions/workflows/tests-fast.yml
[4]: https://github.com/nvm-sh/nvm/releases/tag/v0.40.4
[4]: https://github.com/nvm-sh/nvm/releases/tag/v0.40.5
[Urchin]: https://git.sdf.org/tlevine/urchin
[Fish]: https://fishshell.com
@@ -1114,7 +1127,7 @@ Here's what you will need to do:
If one of these broken versions is installed on your system, the above step will likely still succeed even if you didn't include the `--shared-zlib` flag.
However, later, when you attempt to `npm install` something using your old version of node.js, you will see `incorrect data check` errors.
If you want to avoid the possible hassle of dealing with this, include that flag.
For more details, see [this issue](https://github.com/nodejs/node/issues/39313) and [this comment](https://github.com/nodejs/node/issues/39313#issuecomment-90.40.476)
For more details, see [this issue](https://github.com/nodejs/node/issues/39313) and [this comment](https://github.com/nodejs/node/issues/39313#issuecomment-90.40.576)
- Exit back to your native shell.
@@ -1141,7 +1154,7 @@ Now you should be able to use node as usual.
If you've encountered this error on WSL-2:
```sh
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.4/install.sh | bash
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.5/install.sh | bash
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- 0:00:09 --:--:-- 0curl: (6) Could not resolve host: raw.githubusercontent.com
@@ -1176,7 +1189,7 @@ Currently, the sole maintainer is [@ljharb](https://github.com/ljharb) - more ma
## Project Support
Only the latest version (v0.40.4 at this time) is supported.
Only the latest version (v0.40.5 at this time) is supported.
## Enterprise Support
+1 -1
View File
@@ -33,7 +33,7 @@ nvm_install_dir() {
}
nvm_latest_version() {
nvm_echo "v0.40.4"
nvm_echo "v0.40.5"
}
nvm_profile_is_bash_or_zsh() {
+126 -64
View File
@@ -115,47 +115,62 @@ nvm_get_latest() {
nvm_echo "${NVM_LATEST_URL##*/}"
}
# Every argument is passed through as a literal argv element so that untrusted,
# mirror-supplied version strings in the URLs are never re-parsed by the shell
# (which would allow command substitution / OS command injection).
nvm_download() {
if nvm_has "curl"; then
local CURL_COMPRESSED_FLAG=""
local CURL_HEADER_FLAG=""
local sanitized_header
if [ -n "${NVM_AUTH_HEADER:-}" ]; then
sanitized_header=$(nvm_sanitize_auth_header "${NVM_AUTH_HEADER}")
CURL_HEADER_FLAG="--header \"Authorization: ${sanitized_header}\""
fi
if nvm_curl_use_compression; then
CURL_COMPRESSED_FLAG="--compressed"
fi
local NVM_DOWNLOAD_ARGS
NVM_DOWNLOAD_ARGS=''
for arg in "$@"; do
NVM_DOWNLOAD_ARGS="${NVM_DOWNLOAD_ARGS} \"$arg\""
done
eval "curl -q --fail ${CURL_COMPRESSED_FLAG:-} ${CURL_HEADER_FLAG:-} ${NVM_DOWNLOAD_ARGS}"
elif nvm_has "wget"; then
# Emulate curl with wget
ARGS=$(nvm_echo "$@" | command sed "
s/--progress-bar /--progress=bar /
s/--compressed //
s/--fail //
s/-L //
s/-I /--server-response /
s/-s /-q /
s/-sS /-nv /
s/-o /-O /
s/-C - /-c /
")
if [ -n "${NVM_AUTH_HEADER:-}" ]; then
sanitized_header=$(nvm_sanitize_auth_header "${NVM_AUTH_HEADER}")
ARGS="${ARGS} --header \"${sanitized_header}\""
fi
# shellcheck disable=SC2086
eval wget $ARGS
local sanitized_header
sanitized_header=''
if [ -n "${NVM_AUTH_HEADER:-}" ]; then
sanitized_header="$(nvm_sanitize_auth_header "${NVM_AUTH_HEADER}")"
fi
local NVM_DOWNLOADER
NVM_DOWNLOADER=''
if nvm_has "curl"; then
NVM_DOWNLOADER='curl'
set -- -q --fail "$@"
if nvm_curl_use_compression; then
set -- --compressed "$@"
fi
elif nvm_has "wget"; then
NVM_DOWNLOADER='wget'
# Emulate curl with wget
local NVM_DOWNLOAD_WGET_COUNT
NVM_DOWNLOAD_WGET_COUNT=$#
local NVM_DOWNLOAD_WGET_SKIP
NVM_DOWNLOAD_WGET_SKIP=0
local NVM_DOWNLOAD_WGET_ARG
for NVM_DOWNLOAD_WGET_ARG in "$@"; do
if [ "${NVM_DOWNLOAD_WGET_SKIP}" = '1' ]; then
NVM_DOWNLOAD_WGET_SKIP=0
continue
fi
case "${NVM_DOWNLOAD_WGET_ARG}" in
'--progress-bar') set -- "$@" '--progress=bar' ;;
'--compressed') : ;;
'--fail') : ;;
'-L') : ;;
'-I') set -- "$@" '--server-response' ;;
'-s') set -- "$@" '-q' ;;
'-sS') set -- "$@" '-nv' ;;
'-o') set -- "$@" '-O' ;;
'-C') NVM_DOWNLOAD_WGET_SKIP=1; set -- "$@" '-c' ;;
*) set -- "$@" "${NVM_DOWNLOAD_WGET_ARG}" ;;
esac
done
shift "${NVM_DOWNLOAD_WGET_COUNT}"
fi
if [ -z "${NVM_DOWNLOADER}" ]; then
return 0
fi
if [ -n "${NVM_AUTH_HEADER:-}" ]; then
set -- "$@" --header "Authorization: ${sanitized_header}"
fi
"${NVM_DOWNLOADER}" "$@"
}
nvm_sanitize_auth_header() {
@@ -607,7 +622,7 @@ nvm_rc_version() {
NVMRC_PATH="$(nvm_find_nvmrc)"
if [ ! -e "${NVMRC_PATH}" ]; then
if [ "${NVM_SILENT:-0}" -ne 1 ]; then
nvm_err "No .nvmrc file found"
nvm_err "No version provided and no .nvmrc file found"
fi
return 1
fi
@@ -1912,7 +1927,7 @@ nvm_get_checksum() {
SHASUMS_URL="${MIRROR}/${3}/SHASUMS.txt"
fi
nvm_download -L -s "${SHASUMS_URL}" -o - | command awk "{ if (\"${4}.${5}\" == \$2) print \$1}"
nvm_download -L -s "${SHASUMS_URL}" -o - | command awk -v tarball="${4}.${5}" '{ if (tarball == $2) print $1 }'
}
nvm_print_versions() {
@@ -2491,10 +2506,16 @@ nvm_download_artifact() {
local VERSION
VERSION="${4}"
if [ -z "${VERSION}" ]; then
nvm_err 'A version number is required.'
return 3
fi
case "${VERSION}" in
'')
nvm_err 'A version number is required.'
return 3
;;
*[!0-9A-Za-z._+-]*)
nvm_err 'Invalid version: contains disallowed characters'
return 3
;;
esac
if [ "${KIND}" = 'binary' ] && ! nvm_binary_available "${VERSION}"; then
nvm_err "No precompiled binary available for ${VERSION}."
@@ -3201,7 +3222,7 @@ nvm() {
nvm_echo ' nvm --help Show this message'
nvm_echo ' --no-colors Suppress colored output'
nvm_echo ' nvm --version Print out the installed version of nvm'
nvm_echo ' nvm install [<version>] Download and install a <version>. Uses .nvmrc if available and version is omitted.'
nvm_echo ' nvm install [<version>] Download and install a <version>. Uses .nvmrc if version is omitted; otherwise errors.'
nvm_echo ' The following optional arguments, if provided, must appear directly after `nvm install`:'
nvm_echo ' -s Skip binary download, install from source only.'
nvm_echo ' -b Skip source download, install from binary only.'
@@ -3218,23 +3239,23 @@ nvm() {
nvm_echo ' nvm uninstall <version> Uninstall a version'
nvm_echo ' nvm uninstall --lts Uninstall using automatic LTS (long-term support) alias `lts/*`, if available.'
nvm_echo ' nvm uninstall --lts=<LTS name> Uninstall using automatic alias for provided LTS line, if available.'
nvm_echo ' nvm use [<version>] Modify PATH to use <version>. Uses .nvmrc if available and version is omitted.'
nvm_echo ' nvm use [current | <version>] Modify PATH to use <version>. Uses .nvmrc if version is omitted; otherwise errors.'
nvm_echo ' The following optional arguments, if provided, must appear directly after `nvm use`:'
nvm_echo ' --silent Silences stdout/stderr output'
nvm_echo ' --lts Uses automatic LTS (long-term support) alias `lts/*`, if available.'
nvm_echo ' --lts=<LTS name> Uses automatic alias for provided LTS line, if available.'
nvm_echo ' --save Writes the specified version to .nvmrc.'
nvm_echo ' nvm exec [<version>] [<command>] Run <command> on <version>. Uses .nvmrc if available and version is omitted.'
nvm_echo ' nvm exec [current | <version>] [<command>] Run <command> on <version>. Uses .nvmrc if version is omitted; otherwise errors.'
nvm_echo ' The following optional arguments, if provided, must appear directly after `nvm exec`:'
nvm_echo ' --silent Silences stdout/stderr output'
nvm_echo ' --lts Uses automatic LTS (long-term support) alias `lts/*`, if available.'
nvm_echo ' --lts=<LTS name> Uses automatic alias for provided LTS line, if available.'
nvm_echo ' nvm run [<version>] [<args>] Run `node` on <version> with <args> as arguments. Uses .nvmrc if available and version is omitted.'
nvm_echo ' nvm run [current | <version>] [<args>] Run `node` on <version> with <args> as arguments. Uses .nvmrc if version is omitted; otherwise errors.'
nvm_echo ' The following optional arguments, if provided, must appear directly after `nvm run`:'
nvm_echo ' --silent Silences stdout/stderr output'
nvm_echo ' --lts Uses automatic LTS (long-term support) alias `lts/*`, if available.'
nvm_echo ' --lts=<LTS name> Uses automatic alias for provided LTS line, if available.'
nvm_echo ' nvm current Display currently activated version of Node'
nvm_echo ' nvm current Display the active node version (resolved via $PATH; not affected by .nvmrc).'
nvm_echo ' nvm ls [<version>] List installed versions, matching a given <version> if provided'
nvm_echo ' --no-colors Suppress colored output'
nvm_echo ' --no-alias Suppress `nvm alias` output'
@@ -3255,7 +3276,7 @@ nvm() {
nvm_echo ' nvm install-latest-npm Attempt to upgrade to the latest working `npm` on the current node version'
nvm_echo ' nvm reinstall-packages <version> Reinstall global `npm` packages contained in <version> to current version'
nvm_echo ' nvm unload Unload `nvm` from shell'
nvm_echo ' nvm which [current | <version>] Display path to installed node version. Uses .nvmrc if available and version is omitted.'
nvm_echo ' nvm which [current | <version>] Display path to installed node version. Uses .nvmrc if version is omitted; otherwise errors.'
nvm_echo ' --silent Silences stdout/stderr output when a version is omitted'
nvm_echo ' nvm cache dir Display path to the cache directory for nvm'
nvm_echo ' nvm cache clear Empty cache directory for nvm'
@@ -3317,7 +3338,9 @@ nvm() {
fi
;;
*)
>&2 nvm --help
nvm_err 'Usage: nvm cache dir'
nvm_err ' nvm cache clear'
nvm_err ' Run `nvm --help` for full help.'
return 127
;;
esac
@@ -3573,7 +3596,9 @@ nvm() {
else
{ provided_version="$(nvm_rc_version 3>&1 1>&4)"; } 4>&1
if [ $version_not_provided -eq 1 ] && [ -z "${provided_version}" ]; then
>&2 nvm --help
nvm_err 'Usage: nvm install [<version>]'
nvm_err ' Provide a <version>, or run from a directory containing an .nvmrc file.'
nvm_err ' Run `nvm --help` for full help.'
return 127
fi
fi
@@ -3711,10 +3736,10 @@ nvm() {
nvm install-latest-npm
EXIT_CODE=$?
fi
if [ $EXIT_CODE -ne 0 ] && [ -z "${SKIP_DEFAULT_PACKAGES-}" ]; then
if [ $EXIT_CODE -eq 0 ] && [ -z "${SKIP_DEFAULT_PACKAGES-}" ]; then
nvm_install_default_packages
fi
if [ $EXIT_CODE -ne 0 ] && [ -n "${REINSTALL_PACKAGES_FROM-}" ] && [ "_${REINSTALL_PACKAGES_FROM}" != "_N/A" ]; then
if [ $EXIT_CODE -eq 0 ] && [ -n "${REINSTALL_PACKAGES_FROM-}" ] && [ "_${REINSTALL_PACKAGES_FROM}" != "_N/A" ]; then
nvm reinstall-packages "${REINSTALL_PACKAGES_FROM}"
EXIT_CODE=$?
fi
@@ -3732,7 +3757,7 @@ nvm() {
EXIT_CODE=$?
fi
if [ $EXIT_CODE -ne 0 ] && [ -n "${ALIAS-}" ]; then
if [ $EXIT_CODE -eq 0 ] && [ -n "${ALIAS-}" ]; then
nvm alias "${ALIAS}" "${provided_version}"
EXIT_CODE=$?
fi
@@ -3831,7 +3856,10 @@ nvm() {
;;
"uninstall")
if [ $# -ne 1 ]; then
>&2 nvm --help
nvm_err 'Usage: nvm uninstall <version>'
nvm_err ' nvm uninstall --lts'
nvm_err ' nvm uninstall --lts=<LTS name>'
nvm_err ' Run `nvm --help` for full help.'
return 127
fi
@@ -4020,7 +4048,9 @@ nvm() {
fi
if [ -z "${VERSION}" ]; then
>&2 nvm --help
nvm_err 'Usage: nvm use [<version>]'
nvm_err ' Provide a <version>, or run from a directory containing an .nvmrc file.'
nvm_err ' Run `nvm --help` for full help.'
return 127
fi
@@ -4144,7 +4174,9 @@ nvm() {
VERSION="$(nvm_version "${NVM_RC_VERSION}")" ||:
fi
if [ "${VERSION:-N/A}" = 'N/A' ]; then
>&2 nvm --help
nvm_err 'Usage: nvm run [<version>] [<args>]'
nvm_err ' Provide a <version>, or run from a directory containing an .nvmrc file.'
nvm_err ' Run `nvm --help` for full help.'
return 127
fi
fi
@@ -4158,6 +4190,14 @@ nvm() {
if [ $has_checked_nvmrc -ne 1 ]; then
{ NVM_RC_VERSION="$(NVM_SILENT="${NVM_SILENT:-0}" nvm_rc_version 3>&1 1>&4)"; } 4>&1 && has_checked_nvmrc=1
fi
if [ -z "${NVM_RC_VERSION-}" ]; then
if [ "${NVM_SILENT:-0}" -ne 1 ]; then
nvm_err 'WARNING: `nvm run` was invoked without a version argument and without an .nvmrc file.'
nvm_err ' Falling back to the active node version; this will become an error in a future release.'
nvm_err ' Pass `current` explicitly (e.g. `nvm run current ...`) to silence this warning.'
fi
NVM_RC_VERSION="$(nvm_version current)" ||:
fi
provided_version="${NVM_RC_VERSION}"
IS_VERSION_FROM_NVMRC=1
VERSION="$(nvm_version "${NVM_RC_VERSION}")" ||:
@@ -4215,19 +4255,36 @@ nvm() {
local provided_version
provided_version="$1"
local VERSION_SOURCE
VERSION_SOURCE=''
if [ "${NVM_LTS-}" != '' ]; then
provided_version="lts/${NVM_LTS:-*}"
VERSION="${provided_version}"
VERSION_SOURCE='lts'
elif [ -n "${provided_version}" ]; then
VERSION="$(nvm_version "${provided_version}")" ||:
if [ "_${VERSION}" = '_N/A' ] && ! nvm_is_valid_version "${provided_version}"; then
{ provided_version="$(NVM_SILENT="${NVM_SILENT:-0}" nvm_rc_version 3>&1 1>&4)"; } 4>&1 && has_checked_nvmrc=1
VERSION="$(nvm_version "${provided_version}")" ||:
if [ -n "${provided_version}" ]; then
VERSION_SOURCE='nvmrc'
fi
else
VERSION_SOURCE='arg'
shift
fi
fi
if [ -z "${VERSION_SOURCE}" ]; then
if [ "${NVM_SILENT:-0}" -ne 1 ]; then
nvm_err 'WARNING: `nvm exec` was invoked without a version argument and without an .nvmrc file.'
nvm_err ' Falling back to the active node version; this will become an error in a future release.'
nvm_err ' Pass `current` explicitly (e.g. `nvm exec current ...`) to silence this warning.'
fi
provided_version='current'
VERSION="$(nvm_version current)" ||:
fi
nvm_ensure_version_installed "${provided_version}"
EXIT_CODE=$?
if [ "${EXIT_CODE}" != "0" ]; then
@@ -4362,7 +4419,9 @@ nvm() {
VERSION="${provided_version-}"
fi
if [ -z "${VERSION}" ]; then
>&2 nvm --help
nvm_err 'Usage: nvm which [current | <version>]'
nvm_err ' Provide a <version>, or run from a directory containing an .nvmrc file.'
nvm_err ' Run `nvm --help` for full help.'
return 127
fi
@@ -4459,7 +4518,8 @@ nvm() {
NVM_ALIAS_DIR="$(nvm_alias_path)"
command mkdir -p "${NVM_ALIAS_DIR}"
if [ $# -ne 1 ]; then
>&2 nvm --help
nvm_err 'Usage: nvm unalias <name>'
nvm_err ' Run `nvm --help` for full help.'
return 127
fi
if [ "${1#*\/}" != "${1-}" ]; then
@@ -4496,7 +4556,8 @@ nvm() {
;;
"install-latest-npm")
if [ $# -ne 0 ]; then
>&2 nvm --help
nvm_err 'Usage: nvm install-latest-npm'
nvm_err ' Run `nvm --help` for full help.'
return 127
fi
@@ -4504,7 +4565,8 @@ nvm() {
;;
"reinstall-packages" | "copy-packages")
if [ $# -ne 1 ]; then
>&2 nvm --help
nvm_err "Usage: nvm ${COMMAND} <version>"
nvm_err ' Run `nvm --help` for full help.'
return 127
fi
@@ -4602,7 +4664,7 @@ nvm() {
NVM_VERSION_ONLY=true NVM_LTS="${NVM_LTS-}" nvm_remote_version "${PATTERN:-node}"
;;
"--version" | "-v")
nvm_echo '0.40.4'
nvm_echo '0.40.5'
;;
"unload")
nvm deactivate >/dev/null 2>&1
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "nvm",
"version": "0.40.4",
"version": "0.40.5",
"description": "Node Version Manager - Simple bash script to manage multiple active node.js versions",
"directories": {
"test": "test"
@@ -43,11 +43,11 @@
"homepage": "https://github.com/nvm-sh/nvm",
"devDependencies": {
"dockerfile_lint": "^0.3.4",
"doctoc": "^2.2.1",
"doctoc": "^2.5.0",
"eclint": "^2.8.1",
"markdown-link-check": "^3.14.2",
"replace": "^1.2.2",
"semver": "^7.7.3",
"semver": "^7.8.5",
"urchin": "^0.0.5"
}
}
@@ -0,0 +1,44 @@
#!/bin/sh
set -e
die () { echo "$@" ; exit 1; }
export NVM_DIR="$(cd ../.. && pwd)"
: nvm.sh
\. ../../nvm.sh
\. ../common.sh
HELP="$(nvm --help 2>&1)"
# Signatures for use/exec/run advertise `current` (mirroring `nvm which`).
for EXPECTED in \
'nvm use [current | <version>]' \
'nvm exec [current | <version>] [<command>]' \
'nvm run [current | <version>] [<args>]' \
'nvm which [current | <version>]' \
; do
case "${HELP}" in
*"${EXPECTED}"*) ;;
*) die "nvm --help did not contain signature >${EXPECTED}<" ;;
esac
done
# The .nvmrc fallback is documented as conditional, not free.
case "${HELP}" in
*'Uses .nvmrc if version is omitted; otherwise errors.'*) ;;
*) die "nvm --help did not document the .nvmrc fallback caveat" ;;
esac
# The stale, looser phrasing must be gone.
case "${HELP}" in
*'if available and version is omitted'*) die "nvm --help still contains the old .nvmrc phrasing" ;;
esac
# `nvm current` is documented as resolving via \$PATH, not .nvmrc.
case "${HELP}" in
*'Display the active node version (resolved via $PATH; not affected by .nvmrc).'*) ;;
*) die "nvm --help did not document that 'nvm current' resolves via \$PATH" ;;
esac
@@ -0,0 +1,63 @@
#!/bin/sh
set -ex
die () { echo "$@" ; cleanup ; exit 1; }
cleanup() {
cd "${ORIG_PWD}" 2>/dev/null || true
[ -n "${TMP_DIR-}" ] && rm -rf "${TMP_DIR}"
}
export NVM_DIR="$(cd ../.. && pwd)"
: nvm.sh
\. ../../nvm.sh
\. ../common.sh
ORIG_PWD="$(pwd)"
# Run from a fresh, empty directory so no ambient .nvmrc above the test dir
# can satisfy the lookup and mask the warning.
TMP_DIR="$(mktemp -d)"
cd "${TMP_DIR}" || die "could not cd to temp dir"
EXEC_WARNING='WARNING: `nvm exec` was invoked without a version argument and without an .nvmrc file.'
RUN_WARNING='WARNING: `nvm run` was invoked without a version argument and without an .nvmrc file.'
# `nvm exec` with no version and no .nvmrc should warn on stderr (and fall back).
set +ex # needed for stderr
EXEC_STDERR="$(nvm exec </dev/null 2>&1 1>/dev/null)"
set -ex
case "${EXEC_STDERR}" in
*"${EXEC_WARNING}"*) ;;
*) die "'nvm exec' with no version did not warn; got >${EXEC_STDERR}<" ;;
esac
# `--silent` should suppress the warning.
set +ex # needed for stderr
EXEC_SILENT_STDERR="$(nvm exec --silent </dev/null 2>&1 1>/dev/null)"
set -ex
case "${EXEC_SILENT_STDERR}" in
*WARNING*) die "'nvm exec --silent' should not warn; got >${EXEC_SILENT_STDERR}<" ;;
esac
# `nvm run` with an unresolvable version and no .nvmrc should warn (and fall back).
set +ex # needed for stderr
RUN_STDERR="$(nvm run bogusversion </dev/null 2>&1 1>/dev/null)"
set -ex
case "${RUN_STDERR}" in
*"${RUN_WARNING}"*) ;;
*) die "'nvm run' with no resolvable version did not warn; got >${RUN_STDERR}<" ;;
esac
# `--silent` should suppress the warning.
set +ex # needed for stderr
RUN_SILENT_STDERR="$(nvm run --silent bogusversion </dev/null 2>&1 1>/dev/null)"
set -ex
case "${RUN_SILENT_STDERR}" in
*WARNING*) die "'nvm run --silent' should not warn; got >${RUN_SILENT_STDERR}<" ;;
esac
cleanup
@@ -0,0 +1,68 @@
#!/bin/sh
set -ex
die () { echo "$@" ; cleanup ; exit 1; }
cleanup() {
cd "${ORIG_PWD}" 2>/dev/null || true
[ -n "${TMP_DIR-}" ] && rm -rf "${TMP_DIR}"
}
export NVM_DIR="$(cd ../.. && pwd)"
: nvm.sh
\. ../../nvm.sh
\. ../common.sh
ORIG_PWD="$(pwd)"
# Run from a fresh, empty directory so the "no version + no .nvmrc" cases
# (install/run/which) are not masked by an ambient .nvmrc above the test dir.
TMP_DIR="$(mktemp -d)"
cd "${TMP_DIR}" || die "could not cd to temp dir"
# Asserts a subcommand emits the given focused usage line (not the full help
# dump) on stderr, and exits 127.
assert_usage() {
local EXPECTED_LINE
EXPECTED_LINE="$1"
shift
try_err "$@"
case "${CAPTURED_STDERR}" in
*"${EXPECTED_LINE}"*) ;;
*) die "\`$*\` did not show focused usage >${EXPECTED_LINE}<; got >${CAPTURED_STDERR}<" ;;
esac
# the focused usage should NOT be the full help dump
case "${CAPTURED_STDERR}" in
*'Show this message'*) die "\`$*\` dumped full help instead of a focused usage" ;;
esac
[ "_${CAPTURED_EXIT_CODE}" = "_127" ] \
|| die "\`$*\` expected exit code 127; got ${CAPTURED_EXIT_CODE}"
}
assert_usage 'Usage: nvm cache dir' nvm cache bogus
assert_usage 'Usage: nvm install [<version>]' nvm install
assert_usage 'Usage: nvm run [<version>] [<args>]' nvm run
assert_usage 'Usage: nvm which [current | <version>]' nvm which
assert_usage 'Usage: nvm uninstall <version>' nvm uninstall
assert_usage 'Usage: nvm uninstall <version>' nvm uninstall a b
assert_usage 'Usage: nvm unalias <name>' nvm unalias
assert_usage 'Usage: nvm unalias <name>' nvm unalias a b
assert_usage 'Usage: nvm install-latest-npm' nvm install-latest-npm extra
assert_usage 'Usage: nvm reinstall-packages <version>' nvm reinstall-packages
assert_usage 'Usage: nvm copy-packages <version>' nvm copy-packages a b
# `nvm use` reaches its focused-usage guard only when version resolution returns
# an empty string. From the CLI that cannot happen: an omitted version is caught
# earlier (the `Please see ... nvmrc` branch), and an unresolvable non-empty
# version yields the "N/A" sentinel, never "". The branch is a defensive guard,
# so drive it directly by stubbing the resolver to return empty. Keep this last:
# the stub stays in effect for the rest of the shell.
nvm_match_version() { nvm_echo ''; }
assert_usage 'Usage: nvm use [<version>]' nvm use foo
cleanup
+19 -8
View File
@@ -2,7 +2,7 @@
cleanup () {
unset -f die cleanup
docker stop httpbin && docker rm httpbin
docker rm -f httpbin >/dev/null 2>&1 || true
}
die () { echo "$@" ; cleanup ; exit 1; }
@@ -17,13 +17,24 @@ nvm_download "https://raw.githubusercontent.com/nvm-sh/nvm/HEAD/install.sh" >/de
# nvm_download should fail to download wrong_install.sh
! nvm_download "https://raw.githubusercontent.com/nvm-sh/nvm/HEAD/wrong_install.sh" >/dev/null || die "nvm_download should fail to download no existing file"
# nvm_download should pass when calling with auth header
docker pull kennethreitz/httpbin && SHELL=bash docker run -d --name httpbin -p 80:80 kennethreitz/httpbin
sleep 1 # wait for httpbin to start
NVM_AUTH_HEADER="Bearer test-token" nvm_download "http://127.0.0.1/bearer" > /dev/null || die 'nvm_download with auth header should send correctly'
# nvm_download should fail when calling without auth header
nvm_download "http://127.0.0.1/bearer" > /dev/null && die 'nvm_download with no auth header should not send the header and should fail'
# the auth header checks need a local httpbin container; retry the pull, and
# skip (rather than fail) if the image cannot be pulled or run, so a transient
# Docker registry outage does not fail the suite
httpbin_pulled=0
for i in 1 2 3 4 5; do
if docker pull kennethreitz/httpbin; then httpbin_pulled=1; break; fi
echo "docker pull httpbin failed, attempt $i/5"
sleep $((i * 5))
done
if [ "${httpbin_pulled}" = 1 ] && SHELL=bash docker run -d --name httpbin -p 80:80 kennethreitz/httpbin; then
sleep 1 # wait for httpbin to start
# nvm_download should pass when calling with auth header
NVM_AUTH_HEADER="Bearer test-token" nvm_download "http://127.0.0.1/bearer" > /dev/null || die 'nvm_download with auth header should send correctly'
# nvm_download should fail when calling without auth header
nvm_download "http://127.0.0.1/bearer" > /dev/null && die 'nvm_download with no auth header should not send the header and should fail'
else
echo 'skipping auth header checks: unable to pull or run httpbin'
fi
# ensure quoted extra args remain quoted
nvm_download "https://raw.githubusercontent.com/nvm-sh/nvm/HEAD/install.sh" -o "; die quoted-command-not-quoted" || die 'command failed'
+86
View File
@@ -0,0 +1,86 @@
#!/bin/sh
OLDPATH="$PATH"
WORK="$PWD/nvm_download-noeval-work.$$"
TEST_BIN="$WORK/bin"
ARGV_LOG="$WORK/argv.log"
PROOF="$WORK/nvm_injection_proof"
cleanup() {
unset -f die cleanup
rm -rf "$WORK"
export PATH="$OLDPATH"
}
die () { echo "$@" ; cleanup ; exit 1; }
\. ../../../nvm.sh
OLDPATH="$PATH"
mkdir -p "$TEST_BIN"
# fake curl/wget: record each received argument verbatim, then succeed
{
echo '#!/bin/sh'
echo ': > "$ARGV_LOG"'
echo 'for a in "$@"; do printf "%s\n" "$a" >> "$ARGV_LOG"; done'
echo 'exit 0'
} > "$TEST_BIN/curl"
chmod +x "$TEST_BIN/curl"
cp "$TEST_BIN/curl" "$TEST_BIN/wget"
export ARGV_LOG
export PATH="$TEST_BIN:$OLDPATH"
# given a url containing command-substitution syntax (mirror-supplied)
INJECT_URL="http://example.test/v1\$(touch ${PROOF})/x.tar.gz"
# when nvm_download is invoked (curl path)
rm -f "$PROOF"
nvm_download "$INJECT_URL" -o - || die 'nvm_download (curl) returned nonzero on injection url'
# then the substitution must not have executed
[ ! -e "$PROOF" ] || die "command injection fired via curl path: proof file was created"
# and curl must have received the url as one literal argument
grep -Fxq "$INJECT_URL" "$ARGV_LOG" || die "curl did not receive the url as a single literal argument; got: $(cat "$ARGV_LOG")"
# given a normal download (curl path)
URL="https://nodejs.org/dist/index.tab"
FILE="$WORK/target"
# when invoked with -L -s URL -o FILE
nvm_download -L -s "$URL" -o "$FILE" || die 'nvm_download (curl) returned nonzero on normal url'
# then the url, -o, and output file are passed through verbatim
grep -Fxq "$URL" "$ARGV_LOG" || die "curl did not receive the url; got: $(cat "$ARGV_LOG")"
grep -Fxqe "-o" "$ARGV_LOG" || die "curl did not receive -o; got: $(cat "$ARGV_LOG")"
grep -Fxq "$FILE" "$ARGV_LOG" || die "curl did not receive the output file; got: $(cat "$ARGV_LOG")"
# and curl-style flags are passed through verbatim (curl keeps -s; it is not translated to wget's -q)
grep -Fxqe "-s" "$ARGV_LOG" || die "curl did not receive -s verbatim; got: $(cat "$ARGV_LOG")"
rm -f "$FILE"
# given curl is unavailable (the wget-path calls run with PATH limited to our
# fake wget, so neither the fake nor the system curl is found)
rm -f "$TEST_BIN/curl"
# when nvm_download is invoked with the injection url (wget path)
rm -f "$PROOF"
( PATH="$TEST_BIN"; export PATH; nvm_download "$INJECT_URL" -o - ) || die 'nvm_download (wget) returned nonzero on injection url'
# then the substitution must not have executed
[ ! -e "$PROOF" ] || die "command injection fired via wget path: proof file was created"
grep -Fxq "$INJECT_URL" "$ARGV_LOG" || die "wget did not receive the url as a single literal argument; got: $(cat "$ARGV_LOG")"
# when invoked with -L -C - --progress-bar URL -o FILE (wget path)
( PATH="$TEST_BIN"; export PATH; nvm_download -L -C - --progress-bar "$URL" -o "$FILE" ) || die 'nvm_download (wget) returned nonzero on normal url'
# then flags are translated to wget equivalents
grep -Fxqe "-c" "$ARGV_LOG" || die "wget did not translate -C - to -c; got: $(cat "$ARGV_LOG")"
grep -Fxqe "--progress=bar" "$ARGV_LOG" || die "wget did not translate --progress-bar; got: $(cat "$ARGV_LOG")"
grep -Fxqe "-O" "$ARGV_LOG" || die "wget did not translate -o to -O; got: $(cat "$ARGV_LOG")"
grep -Fxqe "-L" "$ARGV_LOG" && die "wget should drop -L; got: $(cat "$ARGV_LOG")"
grep -Fxqe "-C" "$ARGV_LOG" && die "wget should not pass -C through; got: $(cat "$ARGV_LOG")"
grep -Fxqe "-" "$ARGV_LOG" && die "wget should drop the lone - after -C; got: $(cat "$ARGV_LOG")"
# when invoked with -s (wget path)
( PATH="$TEST_BIN"; export PATH; nvm_download -L -s "$URL" -o "$FILE" ) || die 'nvm_download (wget) returned nonzero on -s url'
# then -s becomes -q
grep -Fxqe "-q" "$ARGV_LOG" || die "wget did not translate -s to -q; got: $(cat "$ARGV_LOG")"
cleanup
echo "nvm_download no eval injection: passed"
@@ -0,0 +1,43 @@
#!/bin/sh
OLDPATH="$PATH"
WORK="$PWD/nvm_download-wgetauth-work.$$"
TEST_BIN="$WORK/bin"
ARGV_LOG="$WORK/argv.log"
cleanup() {
unset -f die cleanup nvm_has
rm -rf "$WORK"
export PATH="$OLDPATH"
}
die () { echo "$@" ; cleanup ; exit 1; }
\. ../../../nvm.sh
OLDPATH="$PATH"
mkdir -p "$TEST_BIN"
# fake wget: record each received argument verbatim, then succeed
{
echo '#!/bin/sh'
echo ': > "$ARGV_LOG"'
echo 'for a in "$@"; do printf "%s\n" "$a" >> "$ARGV_LOG"; done'
echo 'exit 0'
} > "$TEST_BIN/wget"
chmod +x "$TEST_BIN/wget"
export ARGV_LOG
export PATH="$TEST_BIN:$OLDPATH"
# force the wget path while keeping system tools (sed) available for sanitization
nvm_has() { [ "$1" != curl ] && command -v "$1" >/dev/null 2>&1; }
# given an Authorization credential in NVM_AUTH_HEADER
# when nvm_download uses the wget path
NVM_AUTH_HEADER='Bearer test-token' nvm_download "https://nodejs.org/dist/x" -o - || die 'nvm_download (wget) returned nonzero'
# then wget receives a well-formed Authorization header (with the header name, like the curl path)
grep -Fxqe '--header' "$ARGV_LOG" || die "wget did not receive --header; got: $(cat "$ARGV_LOG")"
grep -Fxq 'Authorization: Bearer test-token' "$ARGV_LOG" || die "wget did not receive a well-formed Authorization header; got: $(cat "$ARGV_LOG")"
cleanup
echo "nvm_download wget Authorization header: passed"
@@ -0,0 +1,46 @@
#!/bin/sh
WORK="${TMPDIR:-/tmp}/nvm_version_injection.$$"
PROOF="${WORK}/PWNED"
cleanup () {
unset -f die cleanup nvm_download
rm -rf "${WORK}"
}
die () { echo "$@" ; cleanup ; exit 1; }
\. ../../../nvm.sh
mkdir -p "${WORK}"
export NVM_DIR="${WORK}"
# GHSA-3c52-35h2-gfmm: a mirror-supplied version with shell/awk metacharacters
# must be rejected before it is used in URLs, paths, or awk. Neutralize network.
nvm_download () { return 0; }
# given a version containing command-substitution syntax
# when nvm_download_artifact is asked to download it
# then it is rejected for disallowed characters and nothing is executed
rm -f "${PROOF}"
out="$(nvm_download_artifact node source std 'v1$(touch '"${PROOF}"')' 2>&1 </dev/null)"
case "${out}" in
*'disallowed characters'*) : ;;
*) die "command-substitution version was not rejected; got: ${out}" ;;
esac
[ ! -e "${PROOF}" ] || die 'command-substitution payload executed via nvm_download_artifact'
# and an awk-breakout version is likewise rejected
out="$(nvm_download_artifact node source std 'v1"==$2){system("x")}#' 2>&1 </dev/null)"
case "${out}" in
*'disallowed characters'*) : ;;
*) die "awk-style version was not rejected; got: ${out}" ;;
esac
# and a legitimate nightly version must NOT be rejected by the character guard
out="$(nvm_download_artifact node source std 'v22.0.0-nightly20240101abcdef' 2>&1 </dev/null)"
case "${out}" in
*'disallowed characters'*) die 'a legitimate nightly version was wrongly rejected by the guard' ;;
esac
cleanup
echo 'nvm_download_artifact version injection: passed'
+28
View File
@@ -0,0 +1,28 @@
#!/bin/sh
WORK="${TMPDIR:-/tmp}/nvm_get_checksum_awk.$$"
PROOF="${WORK}/PWNED"
cleanup () {
unset -f die cleanup nvm_download
rm -rf "${WORK}"
}
die () { echo "$@" ; cleanup ; exit 1; }
\. ../../../nvm.sh
mkdir -p "${WORK}"
# GHSA-3c52-35h2-gfmm: nvm_get_checksum must treat the (untrusted, version-derived)
# slug as awk data, never as awk program text.
# given a crafted slug carrying an unconditional awk system() action
# and a mock that supplies one SHASUMS record (so such an action would fire)
nvm_download () { printf 'deadbeef sometarball\n'; }
# when nvm_get_checksum runs with that slug as its 4th argument
rm -f "${PROOF}"
nvm_get_checksum node std v1 'x" == $2) print $1} {system("touch${IFS}'"$PROOF"'")} #' tar.gz >/dev/null 2>&1
# then the injected awk code must not execute
[ ! -e "${PROOF}" ] || die 'awk injection fires in nvm_get_checksum (slug interpolated into awk program text)'
cleanup
echo 'nvm_get_checksum awk injection: passed'
@@ -0,0 +1,39 @@
#!/bin/sh
die () { echo "$@" ; cleanup ; exit 1; }
cleanup() {
cd "${ORIG_PWD}" 2>/dev/null || true
[ -n "${TMP_DIR-}" ] && rm -rf "${TMP_DIR}"
}
: nvm.sh
\. ../../../nvm.sh
\. ../../common.sh
ORIG_PWD="$(pwd)"
# Run from a fresh, empty directory so no ambient .nvmrc above the test dir
# is found by the upward lookup.
TMP_DIR="$(mktemp -d)"
cd "${TMP_DIR}" || die "could not cd to temp dir"
# The message must name both halves of the problem: no argument AND no .nvmrc.
try_err nvm_rc_version
EXPECTED='No version provided and no .nvmrc file found'
[ "_${CAPTURED_STDERR}" = "_${EXPECTED}" ] \
|| die "nvm_rc_version did not print >${EXPECTED}<; got >${CAPTURED_STDERR}<"
[ "_${CAPTURED_EXIT_CODE}" = "_1" ] \
|| die "nvm_rc_version expected exit code 1; got ${CAPTURED_EXIT_CODE}"
# NVM_SILENT suppresses the message but the call still fails.
export NVM_SILENT=1
try_err nvm_rc_version
unset NVM_SILENT
[ -z "${CAPTURED_STDERR}" ] \
|| die "NVM_SILENT nvm_rc_version should be silent; got >${CAPTURED_STDERR}<"
[ "_${CAPTURED_EXIT_CODE}" = "_1" ] \
|| die "NVM_SILENT nvm_rc_version expected exit code 1; got ${CAPTURED_EXIT_CODE}"
cleanup
+7 -4
View File
@@ -17,6 +17,9 @@ NVM_ENV=testing \. ../../install.sh
set -ex
git config --global gc.autoDetach false
git config --global maintenance.auto false
# nvm_do_install is available
type install_nvm_from_git > /dev/null 2>&1 || die 'install_nvm_from_git is not available'
@@ -61,7 +64,7 @@ test_install_data() {
fi
local head_ref="$(git for-each-ref --points-at HEAD --format='%(refname:short)' 'refs/tags/')"
if [ -n "${avoid_ref}" ] && [ "${head_ref}" != "${avoid_ref}"]; then
if [ -n "${avoid_ref}" ] && [ "${head_ref}" != "${avoid_ref}" ]; then
echo "${current_ref}" | grep -q "$avoid_ref" && die "install_nvm_from_git ${message} did clone with unwanted ref ${avoid_ref}"
fi
@@ -94,14 +97,14 @@ test_install() {
test_step "Clones repo $message"
install_nvm_from_git
test_install_data "$(get_head_ref)" "$(get_head_changeset)" "$message" "$ref" "$changeset" "$avoid_ref"
rm -rf "$NVM_DIR"
rm -rf "$NVM_DIR" || { sleep 1; rm -rf "$NVM_DIR"; }
# Ensure it initializes the repository for an empty existing repository
mkdir -p "$NVM_DIR" || die 'Unable to create directory'
test_step "Initialize repo $message"
install_nvm_from_git
test_install_data "$(get_head_ref)" "$(get_head_changeset)" "$message" "$ref" "$changeset" "$avoid_ref"
rm -rf "$NVM_DIR"
rm -rf "$NVM_DIR" || { sleep 1; rm -rf "$NVM_DIR"; }
# Ensure it updates the repository for an existing git repository
git clone "$(nvm_source "git")" -b "v0.36.0" --depth=2 "$NVM_DIR" || die 'Unable to clone repository'
@@ -109,7 +112,7 @@ test_install() {
test_step "Updates repo $message"
install_nvm_from_git
test_install_data "$(get_head_ref)" "$(get_head_changeset)" "$message" "$ref" "$changeset" "$avoid_ref"
rm -rf "$NVM_DIR"
rm -rf "$NVM_DIR" || { sleep 1; rm -rf "$NVM_DIR"; }
}
# Handle latest version
@@ -1,6 +1,27 @@
#!/bin/sh
die () { echo "$@" ; exit 1; }
# State touched by the regression section below; cleanup restores it even on failure.
DEFAULT_PACKAGES_FILE="${NVM_DIR}/default-packages"
DEFAULT_PACKAGES_BACKUP=""
DEFAULT_PACKAGES_WROTE=""
TEST_ALIAS=""
cleanup () {
if [ -n "${DEFAULT_PACKAGES_WROTE}" ]; then
rm -f "${DEFAULT_PACKAGES_FILE}"
DEFAULT_PACKAGES_WROTE=""
fi
if [ -n "${DEFAULT_PACKAGES_BACKUP}" ] && [ -f "${DEFAULT_PACKAGES_BACKUP}" ]; then
mv "${DEFAULT_PACKAGES_BACKUP}" "${DEFAULT_PACKAGES_FILE}"
DEFAULT_PACKAGES_BACKUP=""
fi
if [ -n "${TEST_ALIAS}" ]; then
nvm unalias "${TEST_ALIAS}" > /dev/null 2>&1 || true
TEST_ALIAS=""
fi
}
die () { echo "$@" ; cleanup ; exit 1; }
\. ../../nvm.sh
@@ -44,3 +65,54 @@ nvm use --lts=argon
node --version | grep v4.9.1 > /dev/null || die "nvm ls --lts=argon didn't use v4.9.1"
npm list --global | grep object-is > /dev/null || die "object-is isn't installed"
# Regression: `--reinstall-packages-from` must still migrate packages when the
# target version is *already installed*. See https://github.com/nvm-sh/nvm/issues/3858
# install a fresh global package on the source (v9.7.0) only
nvm use 9.7.0
npm install -g is-nan@1.0.0 || die "npm install -g is-nan failed"
npm list --global | grep is-nan > /dev/null || die "is-nan isn't installed on v9.7.0"
# precondition: the already-installed target (v9.10.0) must not have it yet
nvm use 9.10.0
npm list --global | grep is-nan > /dev/null && die "is-nan should not be installed on v9.10.0 before reinstall"
# target is already installed, so this should report so AND still migrate packages
OUTPUT="$(nvm install --reinstall-packages-from=9.7.0 9.10.0 2>&1)" || die "nvm install --reinstall-packages-from=9.7.0 9.10.0 failed: ${OUTPUT}"
nvm_echo "${OUTPUT}" | grep "is already installed" > /dev/null || die "expected 'already installed' message, got: ${OUTPUT}"
nvm use 9.10.0
npm list --global | grep is-nan > /dev/null || die "is-nan was not migrated to already-installed v9.10.0"
# ...the same is true for default packages: they must install on the already-installed path too.
# back up any real default-packages file, then point it at a package the target lacks
if [ -f "${DEFAULT_PACKAGES_FILE}" ]; then
DEFAULT_PACKAGES_BACKUP="${DEFAULT_PACKAGES_FILE}.3858.bak"
mv "${DEFAULT_PACKAGES_FILE}" "${DEFAULT_PACKAGES_BACKUP}" || die "could not back up ${DEFAULT_PACKAGES_FILE}"
fi
DEFAULT_PACKAGES_WROTE=1
nvm_echo 'object-inspect@1.0.2' > "${DEFAULT_PACKAGES_FILE}"
# precondition: the already-installed target must not have the default package yet
nvm use 9.10.0
npm list --global | grep object-inspect > /dev/null && die "object-inspect should not be installed on v9.10.0 before default-packages test"
nvm install 9.10.0 > /dev/null 2>&1 || die "nvm install 9.10.0 (already installed, default-packages) failed"
nvm use 9.10.0
npm list --global | grep object-inspect > /dev/null || die "default packages were not installed on already-installed v9.10.0"
# restore the default-packages file before the next assertion
cleanup
# ...and `--alias` must be set on the already-installed path too.
TEST_ALIAS='nvm-3858-already-installed'
nvm unalias "${TEST_ALIAS}" > /dev/null 2>&1 || true # ensure a clean precondition
nvm install --alias="${TEST_ALIAS}" 9.10.0 > /dev/null 2>&1 || die "nvm install --alias=${TEST_ALIAS} 9.10.0 (already installed) failed"
TERM=dumb nvm alias "${TEST_ALIAS}" | grep 'v9.10.0' > /dev/null || die "--alias was not set on already-installed v9.10.0"
cleanup