nodejs / docker-node

Official Docker Image for Node.js :whale: :turtle: :rocket:
https://hub.docker.com/_/node/
MIT License
8.28k stars 1.97k forks source link

npm-scripts can't be executed by root on npm 7, 8 #1603

Closed hata6502 closed 1 year ago

hata6502 commented 3 years ago

Environment

Expected Behavior

When execute npm run by root user, the npm-script is also executed by root. It is the behavior of Node 14.

Current Behavior

When execute npm run by root user, the npm-script is executed by node user.

Steps to Reproduce

Clone the example repository.

$ git clone https://github.com/hata6502/node-docker-test.git
$ cd node-docker-test

Then, run the following docker run command.

# Node 14
$ docker run --rm -it -v $(pwd):/usr/src/app node:14 bash -c "cd /usr/src/app && npm i && npm test"
# Node 16
$ docker run --rm -it -v $(pwd):/usr/src/app node:16 bash -c "cd /usr/src/app && npm i && npm test"

Result

$ sudo docker run --rm -it -v $(pwd):/usr/src/app node:14 bash -c "cd /usr/src/app && npm i && npm test"
npm notice created a lockfile as package-lock.json. You should commit this file.
npm WARN docker-test@1.0.0 No description
npm WARN docker-test@1.0.0 No repository field.
npm WARN docker-test@1.0.0 No license field.

up to date in 1.119s
found 0 vulnerabilities

> docker-test@1.0.0 test /usr/src/app
> sleep 10 && touch /root/.npm/test.txt

$ sudo docker run --rm -it -v $(pwd):/usr/src/app node:16 bash -c "cd /usr/src/app && npm i && npm test"
npm WARN ancient lockfile 
npm WARN ancient lockfile The package-lock.json file was created with an old version of npm,
npm WARN ancient lockfile so supplemental metadata must be fetched from the registry.
npm WARN ancient lockfile 
npm WARN ancient lockfile This is a one-time fix-up, please be patient...
npm WARN ancient lockfile 

up to date, audited 1 package in 170ms

found 0 vulnerabilities

> docker-test@1.0.0 test
> sleep 10 && touch /root/.npm/test.txt

touch: cannot touch '/root/.npm/test.txt': Permission denied

The npm-script is executed successfully on Node 14, but a permission error is occured on Node 16.

Show the detail of process by ps -au.

# Node 14
$ docker run --rm -it -v $(pwd):/usr/src/app node:14 bash -c "cd /usr/src/app && npm i; npm test & sleep 5 && ps -au"
# Node 16
$ docker run --rm -it -v $(pwd):/usr/src/app node:16 bash -c "cd /usr/src/app && npm i; npm test & sleep 5 && ps -au"

Result

$ sudo docker run --rm -it -v $(pwd):/usr/src/app node:14 bash -c "cd /usr/src/app && npm i; npm test & sleep 5 && ps -au"
npm notice created a lockfile as package-lock.json. You should commit this file.
npm WARN docker-test@1.0.0 No description
npm WARN docker-test@1.0.0 No repository field.
npm WARN docker-test@1.0.0 No license field.

up to date in 1.066s
found 0 vulnerabilities

> docker-test@1.0.0 test /usr/src/app
> sleep 10 && touch /root/.npm/test.txt

USER         PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root           1  0.3  0.0  17948  2868 pts/0    Ss+  12:11   0:00 bash -c cd /usr/src/app && npm i; npm test & sleep 5 && ps -au
root          19  2.8  0.2 698104 46664 pts/0    Sl+  12:11   0:00 npm
root          31  0.0  0.0   4288   772 pts/0    S+   12:11   0:00 sh -c sleep 10 && touch /root/.npm/test.txt
root          32  0.0  0.0   4196   652 pts/0    S+   12:11   0:00 sleep 10
root          33  0.0  0.0  36640  2820 pts/0    R+   12:11   0:00 ps -au
$ sudo docker run --rm -it -v $(pwd):/usr/src/app node:16 bash -c "cd /usr/src/app && npm i; npm test & sleep 5 && ps -au"
npm WARN ancient lockfile 
npm WARN ancient lockfile The package-lock.json file was created with an old version of npm,
npm WARN ancient lockfile so supplemental metadata must be fetched from the registry.
npm WARN ancient lockfile 
npm WARN ancient lockfile This is a one-time fix-up, please be patient...
npm WARN ancient lockfile 

up to date, audited 1 package in 164ms

found 0 vulnerabilities

> docker-test@1.0.0 test
> sleep 10 && touch /root/.npm/test.txt

USER         PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root           1  0.4  0.0   3740  3016 pts/0    Ss+  12:11   0:00 bash -c cd /usr/src/app && npm i; npm test & sleep 5 && ps -au
root          19  7.2  0.4 703008 68172 pts/0    Sl+  12:11   0:00 npm test
node          31  0.0  0.0   2392   756 pts/0    S+   12:11   0:00 sh -c sleep 10 && touch /root/.npm/test.txt
node          32  0.0  0.0   2300   684 pts/0    S+   12:11   0:00 sleep 10
root          33  0.0  0.0   7644  2712 pts/0    R+   12:11   0:00 ps -au

The npm-script is executed by root user on Node 14, but it is executed by node user on Node 16.

Additional Information

This problem may be not reproduced on Docker Desktop for Mac.

hata6502 commented 3 years ago

This problem seems to be due to npm v7 and v8.

The behavior of npm run with root, is changed between npm v6 and v7.

When git clone https://github.com/hata6502/node-docker-test.git is executed by Ubuntu desktop user, the UID is almost 1000. node-docker-test directory is owned by node user on Docker because node's UID is also 1000. So, npm-scripts is executed by the working-directory owner: node.

hata6502 commented 3 years ago

This behavior may be difficult for Ubuntu Desktop user. I resolved it by sudo chown -R root:root node-docker-test/, but is it the correctly solution?

nschonni commented 3 years ago

https://github.com/nodejs/docker-node/blob/main/docs/BestPractices.md#non-root-user might be related

terencehonles commented 2 years ago

I'm not sure why I just ran into this because I'm pretty sure I had been using node 16, but I think the documentation should probably suggest that starting docker with -u node:node or -u 1000:1000 is appropriate because node will change its user to node even if ran as root in a root container.

razielanarki commented 2 years ago

i'm having the same problem, running docker run node npm i with a "preinstall": "npx npm-force-resolutions" etc in scripts fails either with:

(clickme) output of docker run node npm i (clickme) > ``` > > node-project@1.0.0 preinstall > > npx npm-force-resolutions > > glob error [Error: EACCES: permission denied, scandir '/root/.npm/_logs'] { > errno: -13, > code: 'EACCES', > syscall: 'scandir', > path: '/root/.npm/_logs' > } > npm WARN logfile Error: EACCES: permission denied, scandir '/root/.npm/_logs' > npm WARN logfile error cleaning log files [Error: EACCES: permission denied, scandir '/root/.npm/_logs'] { > npm WARN logfile errno: -13, > npm WARN logfile code: 'EACCES', > npm WARN logfile syscall: 'scandir', > npm WARN logfile path: '/root/.npm/_logs' > npm WARN logfile } > npm ERR! code EACCES > npm ERR! syscall mkdir > npm ERR! path /root/.npm/_cacache/tmp > npm ERR! errno EACCES > npm ERR! > npm ERR! Your cache folder contains root-owned files, due to a bug in > npm ERR! previous versions of npm which has since been addressed. > npm ERR! > npm ERR! To permanently fix this problem, please run: > npm ERR! sudo chown -R 1000:1000 "/root/.npm" > > glob error [Error: EACCES: permission denied, scandir '/root/.npm/_logs'] { > errno: -13, > code: 'EACCES', > syscall: 'scandir', > path: '/root/.npm/_logs' > } > npm WARN logfile Error: EACCES: permission denied, scandir '/root/.npm/_logs' > npm WARN logfile error cleaning log files [Error: EACCES: permission denied, scandir '/root/.npm/_logs'] { > npm WARN logfile errno: -13, > npm WARN logfile code: 'EACCES', > npm WARN logfile syscall: 'scandir', > npm WARN logfile path: '/root/.npm/_logs' > npm WARN logfile } > npm ERR! code EACCES > npm ERR! syscall mkdir > npm ERR! path /root/.npm/_cacache/tmp > npm ERR! errno EACCES > npm ERR! > npm ERR! Your cache folder contains root-owned files, due to a bug in > npm ERR! previous versions of npm which has since been addressed. > npm ERR! > npm ERR! To permanently fix this problem, please run: > npm ERR! sudo chown -R 1000:1000 "/root/.npm" > ```

= output of docker run node whoami

root

= output of docker run node npx -c whoami

node

(clickme) the output of docker run npm config ls -l shows that the default no .npmrc is never overridden for th enode user (clickme) > ``` > ; "default" config from default values > > _auth = (protected) > access = null > all = false > allow-same-version = false > also = null > audit = true > audit-level = null > auth-type = "legacy" > before = null > bin-links = true > browser = null > ca = null > cache = "/root/.npm" > cache-max = null > cache-min = 0 > cafile = null > call = "" > cert = null > ci-name = null > cidr = null > color = true > commit-hooks = true > depth = null > description = true > dev = false > diff = [] > diff-dst-prefix = "b/" > diff-ignore-all-space = false > diff-name-only = false > diff-no-prefix = false > diff-src-prefix = "a/" > diff-text = false > diff-unified = 3 > dry-run = false > editor = "vi" > engine-strict = false > fetch-retries = 2 > fetch-retry-factor = 10 > fetch-retry-maxtimeout = 60000 > fetch-retry-mintimeout = 10000 > fetch-timeout = 300000 > force = false > foreground-scripts = false > format-package-lock = true > fund = true > git = "git" > git-tag-version = true > global = false > global-style = false > globalconfig = "/usr/local/etc/npmrc" > heading = "npm" > https-proxy = null > if-present = false > ignore-scripts = false > include = [] > include-staged = false > include-workspace-root = false > init-author-email = "" > init-author-name = "" > init-author-url = "" > init-license = "ISC" > init-module = "/root/.npm-init.js" > init-version = "1.0.0" > init.author.email = "" > init.author.name = "" > init.author.url = "" > init.license = "ISC" > init.module = "/root/.npm-init.js" > init.version = "1.0.0" > json = false > key = null > legacy-bundling = false > legacy-peer-deps = false > link = false > local-address = null > location = "user" > lockfile-version = null > loglevel = "notice" > logs-max = 10 > ; long = false ; overridden by cli > maxsockets = 15 > message = "%s" > metrics-registry = "https://registry.npmjs.org/" > node-options = null > node-version = "v17.6.0" > noproxy = [""] > npm-version = "8.5.1" > offline = false > omit = [] > only = null > optional = null > otp = null > pack-destination = "." > package = [] > package-lock = true > package-lock-only = false > parseable = false > prefer-offline = false > prefer-online = false > prefix = "/usr/local" > preid = "" > production = null > progress = true > proxy = null > read-only = false > rebuild-bundle = true > registry = "https://registry.npmjs.org/" > save = true > save-bundle = false > save-dev = false > save-exact = false > save-optional = false > save-peer = false > save-prefix = "^" > save-prod = false > scope = "" > script-shell = null > searchexclude = "" > searchlimit = 20 > searchopts = "" > searchstaleness = 900 > shell = "sh" > shrinkwrap = true > sign-git-commit = false > sign-git-tag = false > sso-poll-frequency = 500 > sso-type = "oauth" > strict-peer-deps = false > strict-ssl = true > tag = "latest" > tag-version-prefix = "v" > timing = false > tmp = "/tmp" > umask = 0 > unicode = false > update-notifier = true > usage = false > user-agent = "npm/{npm-version} node/{node-version} {platform} {arch} workspaces/{workspaces} {ci}" > userconfig = "/root/.npmrc" > version = false > versions = false > viewer = "man" > which = null > workspace = [] > workspaces = null > yes = null > > ; "cli" config from command line options > > long = true > ```

(clickme) the output form the next commands confirm that (clickme)

the node user, indeed, runs in the in the root users env

= output of docker run node sh -c 'find ~' > ``` > /root > /root/.bashrc > /root/.profile > /root/.gnupg > /root/.gnupg/random_seed > /root/.gnupg/pubring.kbx > /root/.gnupg/private-keys-v1.d > /root/.gnupg/crls.d > /root/.gnupg/crls.d/DIR.txt > /root/.gnupg/pubring.kbx~ > /root/.gnupg/trustdb.gpg > /root/.npm > /root/.npm/_logs > /root/.npm/_logs/2022-03-02T09_59_07_157Z-debug-0.log > ``` > (note: no `.npmrc` here either) = output of docker run node npx -c 'find ~' > ``` > /root > find: '/root': Permission denied > ``` = output of docker run node npx -c 'find /home/node' > ``` > /home/node > /home/node/.bashrc > /home/node/.profile > /home/node/.bash_logout > ``` = output of docker run node npx -c 'env | sort' > ``` > COLOR=1 > EDITOR=vi > HOME=/root > HOSTNAME=63da0c0a688b > INIT_CWD=/opt/project > NODE=/usr/local/bin/node > NODE_VERSION=17.6.0 > PATH=/opt/project/node_modules/.bin:/opt/node_modules/.bin:/node_modules/.bin:/usr/local/lib/node_modules/npm/node_modules/@npmcli/run-script/lib/node-gyp-bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin > PWD=/opt/project > TERM=xterm > YARN_VERSION=1.22.17 > npm_command=exec > npm_config_cache=/root/.npm > npm_config_call=env | sort > npm_config_global_prefix=/usr/local > npm_config_globalconfig=/usr/local/etc/npmrc > npm_config_init_module=/root/.npm-init.js > npm_config_local_prefix=/opt/project > npm_config_metrics_registry=https://registry.npmjs.org/ > npm_config_node_gyp=/usr/local/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js > npm_config_noproxy= > npm_config_prefix=/usr/local > npm_config_user_agent=npm/8.5.1 node/v17.6.0 linux x64 workspaces/false > npm_config_userconfig=/root/.npmrc > npm_execpath=/usr/local/lib/node_modules/npm/bin/npx-cli.js > npm_lifecycle_event=npx > npm_lifecycle_script=env | sort > npm_node_execpath=/usr/local/bin/node > npm_package_json=/opt/project/package.json > npm_package_name=node-project > npm_package_version=1.0.0 > ```

(logs from on :latest, tested also on :slim,:bullseye,:buster,:alpine,:lts,:10,:14 ... etc)

greghall76 commented 2 years ago

I am having this same problem as rood and a "node" user and regardless of whether npm is therefore trying to write to /tmp/npm_cache or /home/node/.npm/_cacache/tmp

hata6502 commented 1 year ago

This issue is resolved by installing npm v9 🎉 https://github.blog/changelog/2022-10-24-npm-v9-0-0-released/

We believe the changes made lay the ground-work for future improvements to the default npm experience long-term. Notably, Docker users should find this release to to be beneficial as we simplifie file permissions