git packages cannot be deployed with `sudo npm i -g`

cli
help-wanted
priority:medium
triaged

(AJ Jordan) #1

What I Wanted to Do

I want to be able to run e.g. sudo npm install -g strugee/offandonagain.org to deploy directly from GitHub. I expect the module to be installed to /usr/lib/node_modules/offandonagain.org.

What Happened Instead

% sudo npm install -g strugee/offandonagain.org
[sudo] password for alex:
npm ERR! code 128
npm ERR! Command failed: /usr/bin/git submodule update -q --init --recursive
npm ERR! fatal: Could not change back to '/root/.npm/_cacache/tmp/git-clone-70f085c2': Permission denied
npm ERR!

npm ERR! A complete log of this run can be found in:
npm ERR!     /root/.npm/_logs/2018-08-03T19_14_11_747Z-debug.log

Reproduction Steps

  1. Be on a Debian Stretch server
  2. Install Node 10 from NodeSource (I don’t think this is required but it’s the easiest way to get npm because npmjs.com/install.sh fails silently)
  3. Run sudo npm install -g strugee/offandonagain.org

Details

This seems to be a regression - this workflow used to work fine (I’m not sure when, sorry - I believe all 5.x+ versions are broken though). It also seems to have gotten worse over time - I used to be able to do sudo -u root npm i -g ... to work around this, but that seems to have stopped working too. It’s been broken in some form for a long time; I probably should’ve filed a bug report long, long before now but I didn’t. Sorry about that.

AFAICT this is due to npm attempting to not install stuff as root. That is for sure a noble cause, but this is super frustrating because it feels half-baked and like the tool is fighting me - especially since it used to work. (But also, #hugops to you folks and thanks for maintaining this great tool <3)

I think part of the problem here is that npm has two conflicting use cases:

  • Local development on a workstation
  • Server deployment

Discouraging sudo npm i -g is correct for the former, since you’re likely to mess up permissions, but not for the latter. Using a version manager is much more inconvenient on the server because you have to make sure to load up the version manager and set everything up in your init configuration, rather than being able to just use the binary that npm linked into /usr/bin. In addition /usr is a system directory so really only the administrator should be writing to it; it doesn’t make sense to have /usr/lib/node_modules owned by anyone besides root:root.

Here’s the npm-debug.log referenced in “What Happened Instead”:

0 info it worked if it ends with ok
1 verbose cli [ '/usr/bin/node',
1 verbose cli   '/usr/bin/npm',
1 verbose cli   'install',
1 verbose cli   '-g',
1 verbose cli   'strugee/offandonagain.org' ]
2 info using npm@6.2.0
3 info using node@v10.8.0
4 verbose npm-session 034a2d02bcb4deb4
5 silly install loadCurrentTree
6 silly install readGlobalPackageData
7 silly fetchPackageMetaData error for github:strugee/offandonagain.org Command failed: /usr/bin/git submodule update -q --init --recursive
7 silly fetchPackageMetaData fatal: Could not change back to '/root/.npm/_cacache/tmp/git-clone-70f085c2': Permission denied
8 timing stage:rollbackFailedOptional Completed in 0ms
9 timing stage:runTopLevelLifecycles Completed in 12907ms
10 verbose stack Error: Command failed: /usr/bin/git submodule update -q --init --recursive
10 verbose stack fatal: Could not change back to '/root/.npm/_cacache/tmp/git-clone-70f085c2': Permission denied
10 verbose stack
10 verbose stack     at ChildProcess.exithandler (child_process.js:288:12)
10 verbose stack     at ChildProcess.emit (events.js:182:13)
10 verbose stack     at maybeClose (internal/child_process.js:962:16)
10 verbose stack     at Process.ChildProcess._handle.onexit (internal/child_process.js:249:5)
11 verbose cwd /home/alex
12 verbose Linux 4.9.0-7-amd64
13 verbose argv "/usr/bin/node" "/usr/bin/npm" "install" "-g" "strugee/offandonagain.org"
14 verbose node v10.8.0
15 verbose npm  v6.2.0
16 error code 128
17 error Command failed: /usr/bin/git submodule update -q --init --recursive
17 error fatal: Could not change back to '/root/.npm/_cacache/tmp/git-clone-70f085c2': Permission denied
18 verbose exit [ 1, true ]

And here’s some info about permissions:

% sudo ls -la /root/.npm
total 31
drwxr-xr-x 5 root root   6 Aug  3 10:49 .
drwx------ 6 root root  10 Aug  3 10:01 ..
-rw-r--r-- 1 root root 172 Aug  3 12:14 anonymous-cli-metrics.json
drwxr-xr-x 5 root root   5 Aug  3 10:01 _cacache
drwxr-xr-x 2 root root   2 Aug  3 10:17 _locks
drwxr-xr-x 2 root root   7 Aug  3 12:14 _logs
% sudo find /root -not -user root # Outputs nothing
% sudo ls -la /usr/lib/node_modules
total 162
drwxr-xr-x 19 root root 19 Aug  3 11:25 .
drwxr-xr-x 61 root root 89 Aug  3 09:58 ..
drwxr-xr-x  4 root root  8 Aug  3 10:11 bower
drwxr-xr-x  6 root root 16 Aug  3 10:04 bunyan
drwxr-xr-x  5 root root 11 Aug  3 10:04 databank-mongodb
drwxr-xr-x  5 root root  8 Aug  3 10:11 express-generator
drwxr-xr-x  6 root root  9 Aug  3 10:13 generator-bespoke
drwxr-xr-x  4 root root  8 Aug  3 10:14 generator-hubot
drwxr-xr-x  5 root root  8 Aug  3 10:07 gh-pages-server
drwxr-xr-x  6 root root  9 Aug  3 10:14 grunt-cli
drwxr-xr-x  6 root root 12 Aug  3 10:15 gulp
drwxr-xr-x  6 root root 13 Aug  3 10:06 lazymention
drwxr-xr-x  8 root root 17 Aug  3 09:59 npm
drwxr-xr-x  7 root root 10 Aug  3 10:15 nsp
drwxr-xr-x  5 root root 13 Aug  3 10:05 offandonagain.org
drwxr-xr-x 10 root root 31 Aug  3 10:03 pump.io
drwxr-xr-x  8 root root 15 Aug  3 10:15 vows
drwxr-xr-x  4 root root  7 Aug  3 10:16 yo
drwxr-xr-x  3 root root  8 Aug  3 10:17 yosay
% sudo find /usr/lib -not -user root # Outputs nothing

Platform Info

I’ve added additional information at the bottom, so there’s more than the template requires.

The npm install is exactly what comes installed with NodeSource.

$ npm --versions
{ npm: '6.2.0',
  ares: '1.14.0',
  cldr: '33.1',
  http_parser: '2.8.0',
  icu: '62.1',
  modules: '64',
  napi: '3',
  nghttp2: '1.32.0',
  node: '10.8.0',
  openssl: '1.1.0h',
  tz: '2018e',
  unicode: '11.0',
  uv: '1.22.0',
  v8: '6.7.288.49-node.19',
  zlib: '1.2.11' }
$ node -p process.platform
linux
% lsb_release -a
No LSB modules are available.
Distributor ID:	Debian
Description:	Debian GNU/Linux 9.5 (stretch)
Release:	9.5
Codename:	stretch
% apt policy nodejs
nodejs:
  Installed: 10.8.0-1nodesource1
  Candidate: 10.8.0-1nodesource1
  Version table:
 *** 10.8.0-1nodesource1 500
        500 https://deb.nodesource.com/node_10.x stretch/main amd64 Packages
        100 /var/lib/dpkg/status
     8.11.1~dfsg-2~bpo9+1 100
        100 http://ftp.us.debian.org/debian stretch-backports/main amd64 Packages
     4.8.2~dfsg-1 500
        500 http://ftp.us.debian.org/debian stretch/main amd64 Packages

(Kat Marchán) #2

:ohno:

I wouldn’t be surprised if this affects all npm5 versions. And I’m not surprised there’s issues like these with git.

If you’re interested in looking into it, this is all done in pacote. I bet it’s something to do with how it passes uid through to the git child process.