`is-nan@1.0.0` was published on 2014-07-05 and unpublished minutes later
(the registry's `time` map still lists it, but `versions` jumps from `0.0.0` to `1.0.1`),
so `npm install -g is-nan@1.0.0` fails with `ETARGET`,
and the regression test added in ce157343 fails deterministically in every shell.
See https://github.com/nvm-sh/nvm/actions/runs/28407118533
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
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
- 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
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
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
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
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.
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.
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.
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>`).
`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.
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.
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.
`[ "${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)
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.
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.
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.
GNU Tar has `--preserve-permissions` as a default enabled when executed as the superuser (root).
This will cause the binaries to be installed using the permissions (owner and group) as defined in the tarball.
The argument `--no-same-owner` prevents this and will install the binaries as the effective owner/group just like when nvm is executed as a non superuser.
Updated the install from binary test from the installation_node test
suite because this test is run in a docker container as root. Without
--no-same-owner this test will fail beause the binaries of node v0.10.7
are owned by isaacs/admin in the tarball.
The lowercase check was in the `*` catch-all branch of the `case` statement, rejecting any alias name with uppercase characters.
This prevented creating or reading uppercase aliases like `TESTY`.
The check should only apply to `lts/*` patterns, since LTS codenames are always lowercase.
Fixes#3764.
Bug introduced in 9fb9dec710 as part of fixing #3417.
- `nvm-exec` test: expect "Found .nvmrc" message in output, since `nvm_rc_version` now outputs it to stdout via fd 3 redirection (ef162036)
- `nvm_install_binary_nosource`: fix exit code capture by running the command directly instead of inside a subshell with `echo $?` (05d78477)
- `nvm_iojs_version_has_solaris_binary`: bare versions like `v3.3.1` (without `iojs-` prefix) are node versions and should be rejected. The old tests relied on the buggy comparison that let them through (53e6244a)
- `nvm_get_arch_unofficial`: copy `uname` into the chroot. The old test passed only because the unconditional `NVM_ARCH=x64-musl` masked the missing binary, but the `case` fix now requires a real arch to match (39e71eab)
If directory creation fails (e.g., permissions), the script would continue and fail with confusing errors later.
Fail early with a clear error message instead.
Bugs introduced in 68bf93514b, 6cee20a071, and 703babe60a.
- Use `=` instead of `==` for string comparison (POSIX compliance)
- Use `printf '%b'` instead of variable as format string (prevents `%` characters in paths from being interpreted as format specifiers)
- Fix `TRIED_PROFILE` to reference `PROFILE` instead of `NVM_PROFILE` which is known to be empty at that point
Bugs introduced in a24ff3e605, b6f1c156da, and a461a0fffc (PR https://github.com/nvm-sh/nvm/pull/1605).
`${2}` was empty because positional parameters had been consumed by `shift` in the argument parsing loop.
Use `${provided_version}` which holds the resolved alias name.
Bug introduced in 1c00753fd9.
The `*` glob was inside double quotes, preventing shell expansion. `nvm_grep -l` received a literal `*` filename instead of the list of alias files, so aliases pointing to uninstalled versions were never cleaned up.
Bug introduced in 7807a9f09e.
Missing `_` prefix on the right side of the comparison meant the guard clause that rejects non-iojs versions almost never matched, allowing non-iojs versions to fall through.
Bug introduced in 2d692d9d78 / #854.
`return` inside `(...)` subshells only exits the subshell, not the calling function.
Errors in mkdir, download, and checksum verification were silently ignored.
Use `{ ...; }` brace groups instead.
Bug introduced in ba3ad8e460.
When `nosource=1` (the `-b` flag) and binary download fails, the function returned 0 (success) instead of a non-zero exit code, masking the installation failure.
Bug introduced in 4fdef427e4 / #2439.