From 39e71eab492fa882782c8f59a2efbb27d9b839b5 Mon Sep 17 00:00:00 2001 From: Jordan Harband Date: Sat, 14 Mar 2026 12:53:14 -0700 Subject: [PATCH] [Fix] `nvm_get_arch`: only apply musl suffix on x64 Alpine Alpine detection unconditionally set `x64-musl` regardless of actual architecture, which would be incorrect on ARM-based Alpine containers. Bug introduced in https://github.com/nvm-sh/nvm/commit/ef7fc2f2c06ad75fe7fbabf28d427561ae7b007d / #3212. Fixes #3616. --- nvm.sh | 5 ++- test/fast/Unit tests/nvm_get_arch alpine | 48 ++++++++++++++++++++++++ test/mocks/uname_linux_aarch64 | 5 +++ test/mocks/uname_linux_x86_64 | 5 +++ 4 files changed, 62 insertions(+), 1 deletion(-) create mode 100755 test/fast/Unit tests/nvm_get_arch alpine create mode 100755 test/mocks/uname_linux_aarch64 create mode 100755 test/mocks/uname_linux_x86_64 diff --git a/nvm.sh b/nvm.sh index a59ec6d..d853c9d 100755 --- a/nvm.sh +++ b/nvm.sh @@ -2171,7 +2171,10 @@ nvm_get_arch() { fi if [ -f "/etc/alpine-release" ]; then - NVM_ARCH=x64-musl + # Alpine Linux uses musl libc; only x64-musl binaries are available + case "${NVM_ARCH}" in + x64) NVM_ARCH=x64-musl ;; + esac fi nvm_echo "${NVM_ARCH}" diff --git a/test/fast/Unit tests/nvm_get_arch alpine b/test/fast/Unit tests/nvm_get_arch alpine new file mode 100755 index 0000000..560a89a --- /dev/null +++ b/test/fast/Unit tests/nvm_get_arch alpine @@ -0,0 +1,48 @@ +#!/bin/sh + +ORIG_PATH="${PATH}" + +cleanup() { + rm -f ./uname + export PATH="${ORIG_PATH}" +} + +die () { cleanup; echo "$@" ; exit 1; } + +: nvm.sh +\. ../../../nvm.sh + +MOCKS_DIR="$(pwd)/../../mocks" +export PATH=".:${PATH}" + +# On Alpine (where /etc/alpine-release exists), x64 should get -musl suffix +# and arm64 should NOT get -musl suffix. +# On non-Alpine, neither should get -musl. + +if [ -f "/etc/alpine-release" ]; then + # x64 on Alpine should produce x64-musl + ln -sf "${MOCKS_DIR}/uname_linux_x86_64" ./uname + OUTPUT="$(nvm_get_arch)" + rm -f ./uname + [ "_${OUTPUT}" = "_x64-musl" ] || die "x64 on Alpine should be x64-musl, got ${OUTPUT}" + + # aarch64 on Alpine should produce arm64, NOT arm64-musl + ln -sf "${MOCKS_DIR}/uname_linux_aarch64" ./uname + OUTPUT="$(nvm_get_arch)" + rm -f ./uname + [ "_${OUTPUT}" = "_arm64" ] || die "aarch64 on Alpine should be arm64 (no musl suffix), got ${OUTPUT}" +else + # x64 on non-Alpine should produce x64 (no musl suffix) + ln -sf "${MOCKS_DIR}/uname_linux_x86_64" ./uname + OUTPUT="$(nvm_get_arch)" + rm -f ./uname + [ "_${OUTPUT}" = "_x64" ] || die "x64 on non-Alpine should be x64, got ${OUTPUT}" + + # aarch64 on non-Alpine should produce arm64 + ln -sf "${MOCKS_DIR}/uname_linux_aarch64" ./uname + OUTPUT="$(nvm_get_arch)" + rm -f ./uname + [ "_${OUTPUT}" = "_arm64" ] || die "aarch64 on non-Alpine should be arm64, got ${OUTPUT}" +fi + +cleanup diff --git a/test/mocks/uname_linux_aarch64 b/test/mocks/uname_linux_aarch64 new file mode 100755 index 0000000..fc0c32d --- /dev/null +++ b/test/mocks/uname_linux_aarch64 @@ -0,0 +1,5 @@ +if [ "_$1" = "_-m" ]; then + echo "aarch64" +else + echo "Linux hostname 5.15.0-1 #1 SMP aarch64 aarch64 aarch64 GNU/Linux" +fi diff --git a/test/mocks/uname_linux_x86_64 b/test/mocks/uname_linux_x86_64 new file mode 100755 index 0000000..ce40465 --- /dev/null +++ b/test/mocks/uname_linux_x86_64 @@ -0,0 +1,5 @@ +if [ "_$1" = "_-m" ]; then + echo "x86_64" +else + echo "Linux hostname 5.15.0-1 #1 SMP x86_64 x86_64 x86_64 GNU/Linux" +fi