diff --git a/src/util.js b/src/util.js index 61bebe5..5261544 100644 --- a/src/util.js +++ b/src/util.js @@ -241,16 +241,16 @@ function verifyGpgSignature(file, opts = {}) { // binary transform (also no agent) to turn the committed .asc key into the // binary keyring gpgv wants. // - // gpgv treats a --keyring path with NO slash as a name inside ~/.gnupg. On - // Windows the paths are backslash-separated (C:\...), which the MSYS gpgv - // sees as slash-less and mis-resolves. Convert to forward slashes (valid on - // Windows, and gpgv then uses the path literally). const fwd = (p) => p.replace(/\\/g, '/'); + // gpgv reads a leading `scheme:` in --keyring as a resource URL, so a Windows + // C:/... path fails with "invalid key resource URL". The gnupg-ring: prefix + // forces it to take the rest as a literal filename (no-op on POSIX paths). + const keyringArg = `gnupg-ring:${fwd(keyringFile)}`; return download(sigUrl, sigFile, headers) .catch(err => { throw sigError(`could not fetch signature ${sigUrl}: ${err.message}`); }) .then(() => runCommand('gpg', ['--batch', '--no-tty', '--yes', '--dearmor', '-o', keyringFile, keyPath], undefined, undefined, true) .catch(() => { throw sigError(`failed to prepare public key ${keyPath}`); })) - .then(() => runCommand('gpgv', ['--keyring', fwd(keyringFile), fwd(sigFile), fwd(file)], undefined, undefined, true) + .then(() => runCommand('gpgv', ['--keyring', keyringArg, fwd(sigFile), fwd(file)], undefined, undefined, true) .catch(() => { throw sigError(`GPG signature verification failed for ${file}`); })) .then(() => { log(`verified GPG signature for ${file}`); cleanup(); }) .catch(err => { cleanup(); throw err; }); diff --git a/test/gpg-verify.test.js b/test/gpg-verify.test.js index 98a0a92..49eda3e 100644 --- a/test/gpg-verify.test.js +++ b/test/gpg-verify.test.js @@ -114,6 +114,18 @@ describe('verifyGpgSignature (e2e with real gpg)', { skip: !gpgInstalled() }, () await verifyGpgSignature(bin, { binaryUrl, keyPath }); }); + it('resolves when the keyring lives under a path with a colon (drive-letter shape)', async () => { + // A `:` prefix made gpgv reject the keyring as an invalid resource + // URL on Windows. A `C:` dir reproduces it on any platform. + const colonDir = path.join(work, 'C:'); + fs.mkdirSync(colonDir, { recursive: true }); + const bin = path.join(colonDir, 'node-bin-colon'); + fs.writeFileSync(bin, 'colon path bytes'); + sign(bin); + const binaryUrl = `http://${sigHost}/criblio/js2bin/releases/download/v1.0.9/node-bin-colon`; + await verifyGpgSignature(bin, { binaryUrl, keyPath }); + }); + it('uses an explicit sigUrl when provided', async () => { const bin = path.join(work, 'node-bin-explicit'); fs.writeFileSync(bin, 'explicit sig url bytes');