nvm-sh / nvm

Node Version Manager - POSIX-compliant bash script to manage multiple active node.js versions
MIT License
80.36k stars 8.03k forks source link

Installation fails, if not using `bash` (new intended behavior) #2912

Closed DJAlPee closed 5 months ago

DJAlPee commented 2 years ago

Operating system and version:

Using a hardened Alpine container image as base image for our CI/CD container image.

nvm debug output:

```sh /app # nvm debug nvm --version: v0.39.2 $SHELL: $SHLVL: 1 whoami: 'root' ${HOME}: /root ${NVM_DIR}: '${HOME}/.nvm' ${PATH}: ${NVM_DIR}/versions/node/v14.20.1/bin:/usr/local/share/.config/yarn/global/node_modules/.bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin $PREFIX: '' ${NPM_CONFIG_PREFIX}: '' $NVM_NODEJS_ORG_MIRROR: 'https://unofficial-builds.nodejs.org/download/release' $NVM_IOJS_ORG_MIRROR: '' sh: --version: not found shell version: '' uname -a: 'Linux 5.15.64-0-virt #1-Alpine SMP Mon, 05 Sep 2022 08:02:49 +0000 x86_64 GNU/Linux' checksum binary: 'sha256sum' OS version: Authorized uses only. All activity may be monitored and reported. curl: /usr/bin/curl, curl 7.79.1 (x86_64-alpine-linux-musl) libcurl/7.79.1 OpenSSL/1.1.1l zlib/1.2.11 brotli/1.0.9 nghttp2/1.43.0 wget: /usr/bin/wget, GNU Wget 1.21.1 built on linux-musl. git: /usr/bin/git, git version 2.32.3 grep: /bin/grep, BusyBox v1.33.1 () multi-call binary. awk: /usr/bin/awk, BusyBox v1.33.1 () multi-call binary. sed: /bin/sed, BusyBox v1.33.1 () multi-call binary. cut: /usr/bin/cut, cut (GNU coreutils) 8.32 basename: /usr/bin/basename, basename (GNU coreutils) 8.32 rm: /bin/rm, rm (GNU coreutils) 8.32 mkdir: /bin/mkdir, mkdir (GNU coreutils) 8.32 xargs: /usr/bin/xargs, BusyBox v1.33.1 () multi-call binary. nvm current: v14.20.1 which node: ${NVM_DIR}/versions/node/v14.20.1/bin/node which iojs: which npm: ${NVM_DIR}/versions/node/v14.20.1/bin/npm npm config get prefix: ${NVM_DIR}/versions/node/v14.20.1 npm root -g: ${NVM_DIR}/versions/node/v14.20.1/lib/node_modules ```

nvm ls output:

```sh /app # nvm ls -> v14.20.1 * v16.18.0 * v18.11.0 * system * default -> 14 (-> v14.20.1 *) iojs -> N/A (default) node -> stable (-> v18.11.0 *) (default) stable -> 18.11 (-> v18.11.0 *) (default) unstable -> N/A (default) lts/* -> lts/gallium (-> v16.18.0 *) lts/carbon -> v8.17.0 (-> N/A) lts/dubnium -> v10.24.1 (-> N/A) lts/erbium -> v12.22.12 (-> N/A) lts/fermium -> v14.20.1 * lts/gallium -> v16.18.0 * ```

How did you install nvm?

ARG VERSION_NVM=0.39.2
ARG VERSION_NODE="14 16 18"
ENV NVM_NODEJS_ORG_MIRROR=https://unofficial-builds.nodejs.org/download/release
RUN curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v${VERSION_NVM}/install.sh | sh && \
    NVM_DIR=${HOME}/.nvm && \
    source ${HOME}/.nvm/nvm.sh && \
    nvm_get_arch() { nvm_echo "${ARCH_NODE}"; } && \
    for version in ${VERSION_NODE}; do nvm install --latest-npm ${version}; done

Create container image

docker build .

What steps did you perform?

I updated VERSION_NVM from 0.39.1 to 0.39.2 (Patch version change!). Now docker build fails: Error: the install instructions explicitly say to pipe the install script to 'bash'; please follow them. Changing the curl installation part from sh to bash solved this issue, although I want to avoid using bash. Bash is not installed by default on Alpine and could be removed at any time from our hardened container image.

This check had been introduced with this commit: https://github.com/nvm-sh/nvm/commit/39d9a42c359df5dbf37c5000af8192f14a280b94

The commands above had been executed, after sucessfull installation with bash.

What did you expect to happen?

Usage of sh should still be possible, but maybe with a big warning message, that this is not the "official" way to install it.

Is there anything in any of your profile files that modifies the PATH?

Nope.

If you are having installation issues, or getting "N/A", what does curl -I --compressed -v https://nodejs.org/dist/ print out?

```sh /app # curl -I --compressed -v https://nodejs.org/dist/ * Trying 104.20.22.46:443... * Connected to nodejs.org (104.20.22.46) port 443 (#0) * ALPN, offering h2 * ALPN, offering http/1.1 * successfully set certificate verify locations: * CAfile: /etc/ssl/certs/ca-certificates.crt * CApath: none * TLSv1.3 (OUT), TLS handshake, Client hello (1): * TLSv1.3 (IN), TLS handshake, Server hello (2): * TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8): * TLSv1.3 (IN), TLS handshake, Certificate (11): * TLSv1.3 (IN), TLS handshake, CERT verify (15): * TLSv1.3 (IN), TLS handshake, Finished (20): * TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1): * TLSv1.3 (OUT), TLS handshake, Finished (20): * SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384 * ALPN, server accepted to use h2 * Server certificate: * subject: CN=*.nodejs.org * start date: Jan 11 00:00:00 2022 GMT * expire date: Feb 11 23:59:59 2023 GMT * subjectAltName: host "nodejs.org" matched cert's "nodejs.org" * issuer: C=GB; ST=Greater Manchester; L=Salford; O=Sectigo Limited; CN=Sectigo RSA Domain Validation Secure Server CA * SSL certificate verify ok. * Using HTTP2, server supports multiplexing * Connection state changed (HTTP/2 confirmed) * Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0 * Using Stream ID: 1 (easy handle 0x4001cfaa90) > HEAD /dist/ HTTP/2 > Host: nodejs.org > user-agent: curl/7.79.1 > accept: */* > accept-encoding: deflate, gzip, br > * TLSv1.3 (IN), TLS handshake, Newsession Ticket (4): * TLSv1.3 (IN), TLS handshake, Newsession Ticket (4): * old SSL session ID is stale, removing * Connection state changed (MAX_CONCURRENT_STREAMS == 256)! < HTTP/2 200 HTTP/2 200 < date: Fri, 14 Oct 2022 10:20:31 GMT date: Fri, 14 Oct 2022 10:20:31 GMT < content-type: text/html content-type: text/html < last-modified: Fri, 14 Oct 2022 09:05:15 GMT last-modified: Fri, 14 Oct 2022 09:05:15 GMT < cache-control: max-age=14400 cache-control: max-age=14400 < cf-cache-status: HIT cf-cache-status: HIT < age: 2622 age: 2622 < vary: Accept-Encoding vary: Accept-Encoding < strict-transport-security: max-age=31536000; includeSubDomains; preload strict-transport-security: max-age=31536000; includeSubDomains; preload < x-content-type-options: nosniff x-content-type-options: nosniff < server: cloudflare server: cloudflare < cf-ray: 759f953908550b5f-AMS cf-ray: 759f953908550b5f-AMS < content-encoding: br content-encoding: br < * Connection #0 to host nodejs.org left intact ```
ljharb commented 2 years ago

Lots of things aren't installed by default on alpine, but they're required for use of nvm and/or node - all the "minimalism" of alpine seems to get erased once you add all the things your toolchain needs ¯\_(ツ)_/¯

The install script is bash-specific, so it won't work reliably on sh. You could certainly set the BASH_VERSION env var to a fake value before running the install script, but I wouldn't recommend it.

robbyemmert commented 7 months ago

Coupling NVM to a specific shell is a bad idea. NVM already works for zsh on macs, why can't it support sh? Didn't it used to?

I currently can't find a documented way to install NVM in a docker image—which is a pretty common use case. This issue seems to be the limiting factor.

ljharb commented 7 months ago

@robbyemmert nvm itself definitely works on sh - the install script NEVER has worked reliably on anything but bash.

There's an official nvm docker image on dockerhub, and a Dockerfile in this repo: https://github.com/nvm-sh/nvm/blob/HEAD/Dockerfile