linux setfacl is defeated by npm

What I Wanted to Do

install npm module “ungit” global on linux and execute it as any user on the box.

What Happened Instead

execution is not possible as it is only visible to root.

Reproduction Steps

i tried to set an ACL so it is visible to others. npm strangely does not respect it.

$ sudo setfacl -d -m o:rX /usr/lib/node_modules/
$ sudo setfacl -d -m g:root:rX /usr/lib/node_modules/
$ sudo -H npm install -g ungit
$ sudo mkdir /usr/lib/node_modules/what-the-heck
$ ls -l /usr/lib/node_modules/
total 24
drwxr-xr-x   9 root root 4096 29. Jul 11:00 node-gyp
drwxr-xr-x  10 root root 4096 29. Jul 11:00 npm
drwxr-xr-x   3 root root 4096 29. Jul 11:00 semver
drwx------+  9 root root 4096 29. Jul 12:55 ungit
drwxr-xr-x+  2 root root 4096 29. Jul 12:54 what-the-heck
drwxr-xr-x   4 root root 4096 17. Jul 13:44 yarn

Platform Info

$ npm --versions
{ npm: '6.10.2',
  ares: '1.15.0',
  brotli: '1.0.7',
  cldr: '35.1',
  http_parser: '2.8.0',
  icu: '64.2',
  llhttp: '1.1.1',
  modules: '67',
  napi: '4',
  nghttp2: '1.36.0',
  node: '11.15.0',
  openssl: '1.1.1b',
  tz: '2019a',
  unicode: '12.1',
  uv: '1.30.1',
  v8: '7.0.276.38-node.19',
  zlib: '1.2.11' }

$ node -p process.platform
linux
$ umask
0077
$ sudo su -c umask
0077

additional not, a file should be owned by its creator, whoever this is, for security reasons. access should be dealt via “setfacl”:

i saw now a lot of links speaking about permission issues:

setfacl is not supported on Darwin or Windows, so npm doesn’t use it. We do set file modes and ownership directly using the fs APIs available in Node.js, though. Is it possible that your umask is set to 077 instead of 022? npm sets folder permissions to 0o777 & (~process.umask()). If you’ve set a specific umask config for npm, then that’ll override the process one. Try running this:

umask
node -p 'process.umask().toString(8)'
npm config get umask

You’re not the first person to suggest this, and indeed, there’s an RFC for it already.

However, in practice, many people are very confused when they find root-owned files in their $HOME directory, and this can cause problems that bring them here requesting help. The observed expectation (especially of people new to npm and node) is that ownership and permissions will match the folder where the file is being placed.

v6.10.2 made this a contract for cache handling. My intention is to extend the same logic to all the various installed files as well. (So, eg, sudo npm i -g blerg won’t leave user-owned files in /usr/local, and sudo npm i blerg won’t leave root-owned files in the cwd).

and sudo npm i blerg won’t leave root-owned files in the cwd).

That to me seems to be yet another non-standard convention that defies user expectations and standards. When running npm under sudo, the problem was not that the created files in the target of the installation were owned by root. That’s the expectation when you run under sudo, and you should not change that.

The problem was that you implicitly wrote files to hidden locations where the user didn’t expect them to be, e.g., in a persistent dot directory inside the invoking users home directory.

For most users, node_modules is just as “hidden” as ~/.npm. I literally had to help someone just this past weekend at a Node School event try to work out why ./node_modules/* was sometimes root-owned and sometimes not. They just figured some packages require sudo to remove or update.

It’s really not obvious to anyone who doesn’t already know how npm works, even if they do know what sudo is.