diff --git a/nvm.sh b/nvm.sh index 1421d70a..7044ae77 100755 --- a/nvm.sh +++ b/nvm.sh @@ -4273,13 +4273,17 @@ nvm_die_on_prefix() { # # if any of them have a `prefix`, fail. # if any have `globalconfig`, fail also, just in case, to avoid spidering configs. + # + # when deleting, pass `--prefix` so npm does not walk up from `$PWD` and load the project npmrc: + # it is untrusted, and its `userconfig`/`globalconfig`/`location` would choose which file npm rewrites. + # `npm config delete` never edits the project npmrc itself, so that one is left for the user to edit. local NVM_NPM_BUILTIN_NPMRC NVM_NPM_BUILTIN_NPMRC="${NVM_VERSION_DIR}/lib/node_modules/npm/npmrc" if nvm_npmrc_bad_news_bears "${NVM_NPM_BUILTIN_NPMRC}"; then if [ "_${NVM_DELETE_PREFIX}" = "_1" ]; then - npm config --loglevel=warn delete prefix --userconfig="${NVM_NPM_BUILTIN_NPMRC}" - npm config --loglevel=warn delete globalconfig --userconfig="${NVM_NPM_BUILTIN_NPMRC}" + npm config --loglevel=warn delete prefix --userconfig="${NVM_NPM_BUILTIN_NPMRC}" --prefix="${NVM_VERSION_DIR}" + npm config --loglevel=warn delete globalconfig --userconfig="${NVM_NPM_BUILTIN_NPMRC}" --prefix="${NVM_VERSION_DIR}" else nvm_err "Your builtin npmrc file ($(nvm_sanitize_path "${NVM_NPM_BUILTIN_NPMRC}"))" nvm_err 'has a `globalconfig` and/or a `prefix` setting, which are incompatible with nvm.' @@ -4292,8 +4296,8 @@ nvm_die_on_prefix() { NVM_NPM_GLOBAL_NPMRC="${NVM_VERSION_DIR}/etc/npmrc" if nvm_npmrc_bad_news_bears "${NVM_NPM_GLOBAL_NPMRC}"; then if [ "_${NVM_DELETE_PREFIX}" = "_1" ]; then - npm config --global --loglevel=warn delete prefix - npm config --global --loglevel=warn delete globalconfig + npm config --global --loglevel=warn delete prefix --prefix="${NVM_VERSION_DIR}" + npm config --global --loglevel=warn delete globalconfig --prefix="${NVM_VERSION_DIR}" else nvm_err "Your global npmrc file ($(nvm_sanitize_path "${NVM_NPM_GLOBAL_NPMRC}"))" nvm_err 'has a `globalconfig` and/or a `prefix` setting, which are incompatible with nvm.' @@ -4306,8 +4310,8 @@ nvm_die_on_prefix() { NVM_NPM_USER_NPMRC="${HOME}/.npmrc" if nvm_npmrc_bad_news_bears "${NVM_NPM_USER_NPMRC}"; then if [ "_${NVM_DELETE_PREFIX}" = "_1" ]; then - npm config --loglevel=warn delete prefix --userconfig="${NVM_NPM_USER_NPMRC}" - npm config --loglevel=warn delete globalconfig --userconfig="${NVM_NPM_USER_NPMRC}" + npm config --loglevel=warn delete prefix --userconfig="${NVM_NPM_USER_NPMRC}" --prefix="${NVM_VERSION_DIR}" + npm config --loglevel=warn delete globalconfig --userconfig="${NVM_NPM_USER_NPMRC}" --prefix="${NVM_VERSION_DIR}" else nvm_err "Your user’s .npmrc file ($(nvm_sanitize_path "${NVM_NPM_USER_NPMRC}"))" nvm_err 'has a `globalconfig` and/or a `prefix` setting, which are incompatible with nvm.' @@ -4320,8 +4324,9 @@ nvm_die_on_prefix() { NVM_NPM_PROJECT_NPMRC="$(nvm_find_project_dir)/.npmrc" if nvm_npmrc_bad_news_bears "${NVM_NPM_PROJECT_NPMRC}"; then if [ "_${NVM_DELETE_PREFIX}" = "_1" ]; then - npm config --loglevel=warn delete prefix - npm config --loglevel=warn delete globalconfig + nvm_err "Your project npmrc file ($(nvm_sanitize_path "${NVM_NPM_PROJECT_NPMRC}"))" + nvm_err 'has a `globalconfig` and/or a `prefix` setting, which are incompatible with nvm.' + nvm_err 'Project npmrc files are not modified by `--delete-prefix`; edit that file to unset it.' else nvm_err "Your project npmrc file ($(nvm_sanitize_path "${NVM_NPM_PROJECT_NPMRC}"))" nvm_err 'has a `globalconfig` and/or a `prefix` setting, which are incompatible with nvm.' diff --git a/test/fast/Unit tests/nvm_die_on_prefix b/test/fast/Unit tests/nvm_die_on_prefix index 11237fde..44691446 100755 --- a/test/fast/Unit tests/nvm_die_on_prefix +++ b/test/fast/Unit tests/nvm_die_on_prefix @@ -209,6 +209,52 @@ Run \`foo\` to unset it." [ "_$CAPTURED_EXIT_CODE" = "_10" ] || die "'nvm_die_on_prefix 0 foo' with user .npmrc that has globalconfig did not exit with 10; got '$CAPTURED_EXIT_CODE'" ) +# "delete the prefix": npm must not load the (untrusted) project npmrc, which could otherwise choose +# the file npm rewrites via `userconfig`/`globalconfig`/`location`, and the project npmrc is never edited +( + DELETE_DIR="${TEST_DIR}/delete-prefix" + DELETE_VERSION_DIR="${DELETE_DIR}/version" + DELETE_PROJECT_DIR="${DELETE_DIR}/project" + DELETE_HOME="${DELETE_DIR}/home" + mkdir -p "${DELETE_VERSION_DIR}/etc" "${DELETE_VERSION_DIR}/lib/node_modules/npm" "${DELETE_PROJECT_DIR}" "${DELETE_HOME}" + export HOME="${DELETE_HOME}" + echo 'prefix=garbage' > "${DELETE_VERSION_DIR}/lib/node_modules/npm/npmrc" + echo 'prefix=garbage' > "${DELETE_VERSION_DIR}/etc/npmrc" + echo 'prefix=garbage' > "${DELETE_HOME}/.npmrc" + + cd "${DELETE_PROJECT_DIR}" || die 'could not cd to the project dir' + touch package.json + PROJECT_NPMRC_CONTENTS="prefix=garbage +userconfig=${DELETE_HOME}/victim +location=global +globalconfig=${DELETE_HOME}/victim" + echo "${PROJECT_NPMRC_CONTENTS}" > .npmrc + + NPM_CALLS="${DELETE_DIR}/npm-calls" + npm() { + echo "$*" >> "${NPM_CALLS}" + } + + try_err nvm_die_on_prefix 1 foo "${DELETE_VERSION_DIR}" + + EXPECTED_OUTPUT="Your project npmrc file ($(nvm_sanitize_path "${DELETE_PROJECT_DIR}")/.npmrc) +has a \`globalconfig\` and/or a \`prefix\` setting, which are incompatible with nvm. +Project npmrc files are not modified by \`--delete-prefix\`; edit that file to unset it." + [ "_$CAPTURED_STDERR" = "_$EXPECTED_OUTPUT" ] || die "'nvm_die_on_prefix 1 foo' with a project .npmrc that has prefix did not warn with '$EXPECTED_OUTPUT'; got '$CAPTURED_STDERR'" + [ "_$CAPTURED_EXIT_CODE" = "_0" ] || die "'nvm_die_on_prefix 1 foo' with a project .npmrc that has prefix did not exit with 0; got '$CAPTURED_EXIT_CODE'" + + EXPECTED_OUTPUT="config --loglevel=warn delete prefix --userconfig=${DELETE_VERSION_DIR}/lib/node_modules/npm/npmrc --prefix=${DELETE_VERSION_DIR} +config --loglevel=warn delete globalconfig --userconfig=${DELETE_VERSION_DIR}/lib/node_modules/npm/npmrc --prefix=${DELETE_VERSION_DIR} +config --global --loglevel=warn delete prefix --prefix=${DELETE_VERSION_DIR} +config --global --loglevel=warn delete globalconfig --prefix=${DELETE_VERSION_DIR} +config --loglevel=warn delete prefix --userconfig=${DELETE_HOME}/.npmrc --prefix=${DELETE_VERSION_DIR} +config --loglevel=warn delete globalconfig --userconfig=${DELETE_HOME}/.npmrc --prefix=${DELETE_VERSION_DIR}" + OUTPUT="$(cat "${NPM_CALLS}")" + [ "_$OUTPUT" = "_$EXPECTED_OUTPUT" ] || die "'nvm_die_on_prefix 1 foo' did not run npm with a pinned \`--prefix\` (and never for the project npmrc): expected '$EXPECTED_OUTPUT'; got '$OUTPUT'" + + [ "_$(cat .npmrc)" = "_${PROJECT_NPMRC_CONTENTS}" ] || die "'nvm_die_on_prefix 1 foo' edited the project .npmrc; got '$(cat .npmrc)'" +) || die "'nvm_die_on_prefix 1 foo' let a project .npmrc influence npm" + # nvm_npmrc_bad_news_bears matches `^(prefix|globalconfig) *=` NPMRC="${TEST_DIR}/bad-news.npmrc" printf 'prefix=x\n' > "${NPMRC}"