np icon indicating copy to clipboard operation
np copied to clipboard

Support GPG password prompt

Open ghengeveld opened this issue 8 years ago • 15 comments

Issuehunt badges

I'm trying to publish this package using np major, but it hangs on the "Bumping version" step. When I exit the process and run git log I see that it has created a commit for v1.0.0, but it hasn't created a tag, so it seems to fail on the tagging part. I'm using git v2.7.0 and Node v6.3.1.

$ np major
 ✔ Prerequisite check
 ✔ Git
 ✔ Cleanup
 ✔ Installing dependencies
 ✔ Running tests
 ✔ Prerequisite check
 ✔ Git
 ✔ Cleanup
 ✔ Installing dependencies
 ✔ Running tests
 ⠦ Bumping version
   → v1.0.0
   Publishing package
   Pushing tags

Is there a debug/verbose flag that I can set to get more detailed output? Could the precommit hook I have in place (through husky) have something to do with it?

For now I have tagged and published my package manually.


IssueHunt Summary

Backers (Total: $60.00)

Submitted pull Requests


Become a backer now!

Or submit a pull request to get the deposits!

Tips

ghengeveld avatar Aug 09 '16 10:08 ghengeveld

I suspect it's something with the precommit hook. The "Bumping version" step just calls npm version major which handles all that. We don't have any verbose flag, but that could definitely be useful.

sindresorhus avatar Aug 09 '16 12:08 sindresorhus

Right, I tried npm version patch. I have npm configured to use GPG commit signing, so it asks me to enter my password. np does not allow me to provide that password, therefore it hangs waiting for stdin. I'll try to replace the secret key to not require a password.

You need a passphrase to unlock the secret key for
user: "******"
2048-bit RSA key, ID ******, created 2015-07-20

ghengeveld avatar Aug 09 '16 12:08 ghengeveld

Yeah, we should support entering GPG password. I don't have GPG set up, so I won't be able to do it, but pull request welcome :)

sindresorhus avatar Aug 09 '16 12:08 sindresorhus

Okay, I'm willing to look into it. Looks like this is a listr or execa thing.

ghengeveld avatar Aug 09 '16 12:08 ghengeveld

After some fiddling, here's what I came up with:

task: () => new Observable(observer => {
    const child = execa('npm', ['version', 'patch', '--force']);
    let data = '';
    child.stdout.on('data', chunk => {
        data += chunk.toString();
        observer.next(data);
    });
    child.stdout.on('close', () => {
        observer.complete();
    })
    process.stdin.setRawMode(true);
    process.stdin.pipe(child.stdin);
    setTimeout(observer.complete, 10000); // in case the child never exits
})

While I tested this to work with a simple node script that prompts for a password and exits on newline, it doesn't work with npm version. For some reason npm version only sends the bumped version number to stdout, not the password prompt. The password prompt only appears in my shell after the parent process finished.

Update: After investigating npm version, it seems the chain method they use gobbles up the stdout. If I wrap my node script in a chain, the script itself still works normally when called directly, but fails to output data when I call it with execa (child.stdout.on('data', () => { ... }) is never invoked).

ghengeveld avatar Aug 09 '16 14:08 ghengeveld

Here's what works when I use my node script wrapped in a chain (like npm version):

task: () => new Observable(observer => {
    const child = spawn('node', ['password'], { stdio: [process.stdin, 'pipe', 'pipe'] });
    const timeout = setTimeout(() => {
        child.kill();
        observer.error('Error: Task timed out');
    }, 60000);

    let data = '';
    child.stdout.on('data', chunk => {
        data += chunk.toString();
        observer.next(data);
    });
    child.stderr.on('data', chunk => {
        clearTimeout(timeout);
        child.kill();
        observer.error(chunk.toString());
    });
    child.on('close', () => {
        clearTimeout(timeout);
        child.kill();
        observer.complete();
    });
})

Unfortunately this doesn't work with npm version because it sends the GPG prompt via stderr instead of stdout. Also it is limited to only one line because that's all Listr supports. I'm kind of out of ideas other than dropping Listr or forking it to add support for this kind of thing, but that seems a bit drastic.

ghengeveld avatar Aug 10 '16 11:08 ghengeveld

Another idea is to just recommend people use a GPG GUI password prompt.

@SamVerschueren Maybe Listr could have a method to make the child-process output fullscreen and replace the list temporarily? Might be overkill, but I could see other tools wanting prompts of some kind.

sindresorhus avatar Aug 12 '16 22:08 sindresorhus

I totally missed this issue. But since today, Listr supports custom renderers and even 3rd party renderers. The default renderer for example is extracted to a separate package listr-update-renderer. So it should be possible to do something like this without messing with the internals of Listr.

SamVerschueren avatar Sep 15 '16 21:09 SamVerschueren

Just typing in the password works! In case that wasn't known.

silvenon avatar Sep 26 '16 09:09 silvenon

@silvenon Got the same issue and blind typing on Bumping version did the trick 😄

0xjjpa avatar Nov 26 '16 11:11 0xjjpa

It worked for me too, but it would be nice if np was explicitly asking a passphrase. Do you think it would be easy to detect commit signing and do so?

ngryman avatar Feb 23 '17 11:02 ngryman

In case someone wants to tackle this, I created listr-input which we use for the one-time password of npm. Should be doable with that one I guess.

SamVerschueren avatar Feb 17 '18 15:02 SamVerschueren

@issuehunt has funded $60.00 to this issue.


IssueHuntBot avatar Apr 11 '19 12:04 IssueHuntBot

I start working on this issue. I actually had the same issue with using pinentry-curses or pinentry-tty as the pinentry-program. The cause was the listr-update-renderer, which overwrites the output of the pinentry-program.

My solution would look like:

  1. set a suspend flag for the listr-tasks
  2. suspend the update-log, if suspend-flag for this task is active
  3. if the task is completed, activate the listr-update-renderer again

bunysae avatar Aug 18 '19 17:08 bunysae

Another idea is to just recommend people use a GPG GUI password prompt.

Per this, using a GUI password prompt works fine. On my macOS machine, I installed brew install pinentry-mac, and configured it with GPG by adding to ~/.gnupg/gpg-agent.conf

pinentry-program /usr/local/bin/pinentry-mac

philihp avatar May 06 '20 10:05 philihp