Search code examples
npmrootnpm-scripts

Why does running "npm run <script>" as root switch user?


I setup a new project inside an alpine image (node:16-alpine), in /app2, with the following structure:

- node_modules
  - .bin
    - dummy
- package.json

package.json:

{
  ...
  "scripts": {
    "dummy": "dummy",
  },
  ...
}

dummy:

#!/usr/bin/env node

setInterval(() => console.log("."), 1000)

Now when i run npm run dummy with root user, instead of the root user, the node command will run with whatever user owns the project root directory. Eg:

/app2 # ls -lah
...    
drwxr-xr-x    3 node2    node        4.0K Jan 17 08:27 .
...

/app2 # whoami
root

/app2 # npm run dummy
...

# in a different terminal:
/app2 # ps x
...
  816 root      0:00 npm run dummy
  827 node2     0:00 node /app2/node_modules/.bin/dummy
...

This does not happen if I'm not running npm with root (eg: su node && npm run dummy will run as node user, and not node2).

Why is this? Does any know if this is documented anywhere? Or how can I run the scripts as root? (i know it's not recommended, but it's inside a docker container and for development only)


Solution

  • This happens in @npmcli/promise-spawn

     const isRoot = process.getuid && process.getuid() === 0
     const { uid, gid } = isRoot ? inferOwner.sync(cwd) : {}
    

    You cannot find documentation as this behavior was removed a while ago.

    This is an old note removed in that commit that described the behavior you see:

    Note: When the current user is root, this will use infer-owner to find the owner of the current working directory, and run with that effective uid/gid. Otherwise, it runs as the current user always. (This helps prevent doing git checkouts and such, and leaving root-owned files lying around in user-owned locations.)