nodejs/corepack

Can't use `pnpm` via corepack when `COREPACK_HOME` is read-only.

momesana opened this issue · 5 comments

(originally posted as a discussion post here: https://github.com/orgs/nodejs/discussions/52547)

We have a build infrastructure where we install Node.js and pnpm (via corepack) into a build folder which is then subsequently used to run install commands etc. COREPACK_HOME is also placed there (inside the Node.js installation folder) and It's never expected to be mutated after the initial installation thus the entire folder is marked read-only. This also makes it more likely to have reproducible builds. The issue we are facing now is that running corepack pnpm (or pnpm directly) with COREPACK_HOME set to the previously mentioned read-only folder results in an error along the lines of:

Internal Error: EACCES: permission denied, open '/corepack_cache/lastKnownGood.json'
    at async Object.open (node:internal/fs/promises:637:25)
    at async Engine.getDefaultVersion (/node/v21.7.3/lib/node_modules/corepack/dist/lib/corepack.cjs:23337:29)
    at async executePackageManagerRequest (/node/v21.7.3/lib/node_modules/corepack/dist/lib/corepack.cjs:24207:28)
    at async BinaryCommand.validateAndExecute (/node/v21.7.3/lib/node_modules/corepack/dist/lib/corepack.cjs:21173:22)
    at async _Cli.run (/node/v21.7.3/lib/node_modules/corepack/dist/lib/corepack.cjs:22148:18)
    at async Object.runMain (/node/v21.7.3/lib/node_modules/corepack/dist/lib/corepack.cjs:24279:12)

Any ideas why this is the case? Why should corepack need write-access to lastKnownGood.json even though I have set COREPACK_DEFAULT_TO_LATEST to 0 and don't even allow network access? Is there a way to prevent that from happening without bypassing corepack entirely?

How to reproduce it

We can easily reproduce the issue by creating a docker environment (I've used the latest ubuntu image here):

docker run --rm -it ubuntu bash

then installing Node.js and pnpm in the docker environment, creating a guest user and switching to the guest user account

NODE_VERSION="v21.7.3" # v20.12.2 or v21.7.3
PNPM_VERSION="8.14.3"
ARCH="linux-x64"
ARCHIVE="node-${NODE_VERSION}-${ARCH}.tar.xz"
NODE_HOME=/node/${NODE_VERSION}
export PATH="${NODE_HOME}/bin:${PATH}"
export COREPACK_HOME=/corepack_cache
export COREPACK_DEFAULT_TO_LATEST=0
export COREPACK_ENABLE_NETWORK=0


# Install nodejs
apt -y update
apt -y install curl xz-utils

mkdir downloads
curl https://nodejs.org/dist/${NODE_VERSION}/${ARCHIVE} -o ./downloads/${ARCHIVE}

mkdir -p $NODE_HOME
tar xvf /downloads/${ARCHIVE} -C $NODE_HOME --strip-components 1


echo "node version: $(node --version)"
chmod -R a-w ${NODE_HOME}


# install pnpm
mkdir ${COREPACK_HOME}
COREPACK_ENABLE_NETWORK=1 corepack install -g pnpm@${PNPM_VERSION}
chmod -R a-w ${COREPACK_HOME}

# create guest user
adduser -gecos "" --disabled-password guest
usermod --password $(echo strengGeheim | openssl passwd -1 -stdin) guest # this is not really necessary but let's do it nonetheless

# Switch to guest environment
su guest

Now we can try to run pnpm after setting COREPACK_HOME etc. again

# set environment variables again
NODE_VERSION="v21.7.3" # set to same value as above
PNPM_VERSION="8.14.3"
ARCH="linux-x64"
NODE_HOME=/node/${NODE_VERSION}
export PATH="${NODE_HOME}/bin:${PATH}"
export COREPACK_HOME=/corepack_cache
export COREPACK_DEFAULT_TO_LATEST=0
export COREPACK_ENABLE_NETWORK=0

# now reproduce the error by something as trivial
corepack pnpm --version

which will spit out one of the above error.

or is that already the fix?

And after a cursory glance at the code I'd assume that the following mode should be 'r' instead of 'r+':

let lastKnownGoodFile = await getLastKnownGoodFile(`r+`).catch(err => {

I've built and used the newest master revision from the corepack repo and replaced the one in the image with that and then it works so I assume the issue has been addressed by "c449adc feat: separate read and write operations on lastKnownGood.json (#446)"

Closed it as it's effectively a duplicate of #183

Will this be in node 20? It was merged only 3 days after v20.12.2 was released.

Will this be in node 20? It was merged only 3 days after v20.12.2 was released.

it was released with Node 22.1.0 if I recollect right.