Skip to content

[BUG] sudo prompt is not shown in scripts, causing install and tests to hang #2887

Closed
@aral

Description

@aral

Current Behavior:

If a command in an npm script (e.g., postinstall or test) causes a sudo prompt to be shown, the prompt is not presented to the person and the script hangs.

For example, if I have a postinstall script and I run npm install and some command in the script (e.g., an execFileSync()) requires sudo permissions, I will never the sudo prompt and the installation will hang.

Expected Behavior:

The sudo prompt should be shown to the person.

Steps To Reproduce:

  1. Create a folder called my-module
  2. Run npm init -y to create your package.json file
  3. Add the following scripts section to your package file:
  "scripts": {
    "postinstall": "node ./postinstall.js"
  }
  1. Create the postinstall.js file with the following contents:
import childProcess from 'child_process'
childProcess.execFileSync('sudo', ['ls', '/root'])
  1. Run npm i (and note that you get prompted for the sudo password as expected and that installation succeeds once you enter it)
  2. Create a different directory in the same parent directory as my-module called the-bug
  3. Run npm init -y from the the-bug directory
  4. In the the-bug directory, type npm i ../my-module to install your module

What should happen

You should get prompted for your sudo password and be able to enter it and installation should succeed when you do.

What actually happens

You don’t see the sudo prompt and the installation hangs.

Workaround

Until this bug is fixed, you can use the sudo-prompt module to display a graphical sudo prompt in your lifecycle scripts.

The following snippet from the real-world use case where I encountered this bug (in my Auto Encrypt Localhost library that uses mkcert to provision local TLS certificates) demonstrates the workaround:

import sudoPrompt from 'sudo-prompt'
import { binaryPath as mkcertBinary } from '../lib/mkcert.js'
//…
await (() => {
  return new Promise((resolve, reject) => {
    sudoPrompt.exec(`${mkcertBinary} -install`, {name: 'Auto Encrypt Localhost'}, function(error, stdout, stderr) {
      if (error) reject(error)
      console.log(stdout)
      resolve()
    })
  })
})()

(Above is not a true workaround as it does not behave exactly like sudo on Linux, causing file permission errors).

Other notes

  • Note that if you have passwordless sudo set up on your system, you will not encounter this bug.

Update

Also just ran into this issue also when running tests, which actually makes it a much more important bug. So if your Node app at any point requires sudo privileges, this means that your test will fail also as they do not show the sudo password prompt.

As a workaround for that, do something that requires the sudo prompt before your test. e.g., in your package file:

"scripts": {
  "test": "sudo echo 'Got sudo privileges.\n' && esm-tape-runner 'test/**/*.js' | tap-monkey"
}

That will unlock sudo and you should be able to run your tests before the timeout.

(Or, of course, use passwordless sudo on your dev machine but you cannot rely on everyone doing this. Most folks probably won’t and they’ll just think that your tests are hanging. So until this bug is fixed, your best bet is to use a workaround similar to the one above.)

Environment:

  • OS: elementary OS 5.1.7 Hera x86_64 (based on Ubuntu 18.04)
  • Node: 14.16.0
  • npm: 7.6.0

Metadata

Metadata

Assignees

No one assigned

    Labels

    Release 7.xwork is associated with a specific npm 7 release

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions