UNPKG

renovate

Version:

Automated dependency updates. Flexible so you don't need to be.

123 lines 5.22 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.setPrivateKey = setPrivateKey; exports.writePrivateKey = writePrivateKey; exports.configSigningKey = configSigningKey; const tslib_1 = require("tslib"); const node_os_1 = tslib_1.__importDefault(require("node:os")); const is_1 = tslib_1.__importDefault(require("@sindresorhus/is")); const fs_extra_1 = tslib_1.__importDefault(require("fs-extra")); const upath_1 = tslib_1.__importDefault(require("upath")); const error_messages_1 = require("../../constants/error-messages"); const logger_1 = require("../../logger"); const exec_1 = require("../exec"); const regex_1 = require("../regex"); const sanitize_1 = require("../sanitize"); const sshKeyRegex = (0, regex_1.regEx)(/-----BEGIN ([A-Z ]+ )?PRIVATE KEY-----.*?-----END ([A-Z]+ )?PRIVATE KEY-----/, 's'); let gitPrivateKey; class PrivateKey { key; keyId; constructor(key) { this.key = key; (0, sanitize_1.addSecretForSanitizing)(this.key, 'global'); logger_1.logger.debug('gitPrivateKey: successfully set (but not yet written/configured)'); } async writeKey() { try { this.keyId ??= await this.importKey(); logger_1.logger.debug('gitPrivateKey: imported'); } catch (err) { logger_1.logger.warn({ err }, 'gitPrivateKey: error importing'); throw new Error(error_messages_1.PLATFORM_GPG_FAILED); } } async configSigningKey(cwd) { logger_1.logger.debug('gitPrivateKey: configuring commit signing'); // TODO: types (#22198) await (0, exec_1.exec)(`git config user.signingkey ${this.keyId}`, { cwd }); await (0, exec_1.exec)(`git config commit.gpgsign true`, { cwd }); await (0, exec_1.exec)(`git config gpg.format ${this.gpgFormat}`, { cwd }); } } class GPGKey extends PrivateKey { gpgFormat = 'openpgp'; constructor(key) { super(key.trim()); } async importKey() { const keyFileName = upath_1.default.join(node_os_1.default.tmpdir() + '/git-private-gpg.key'); await fs_extra_1.default.outputFile(keyFileName, this.key); const { stdout, stderr } = await (0, exec_1.exec)( // --batch --no-tty flags allow Renovate to skip warnings about unsupported algorithms in the key `gpg --batch --no-tty --import ${keyFileName}`); logger_1.logger.debug({ stdout, stderr }, 'Private key import result'); await fs_extra_1.default.remove(keyFileName); return `${stdout}${stderr}` .split(regex_1.newlineRegex) .find((line) => line.includes('secret key imported')) ?.replace('gpg: key ', '') .split(':') .shift(); } } class SSHKey extends PrivateKey { gpgFormat = 'ssh'; async importKey() { const keyFileName = upath_1.default.join(node_os_1.default.tmpdir() + '/git-private-ssh.key'); if (await this.hasPassphrase(keyFileName)) { throw new Error('SSH key must have an empty passhprase'); } await fs_extra_1.default.outputFile(keyFileName, this.key.replace(/\n?$/, '\n')); process.on('exit', () => fs_extra_1.default.removeSync(keyFileName)); await fs_extra_1.default.chmod(keyFileName, 0o600); // HACK: `git` calls `ssh-keygen -Y sign ...` internally for SSH-based // commit signing. Technically, only the private key is needed for signing, // but `ssh-keygen` has an implementation quirk which requires also the // public key file to exist. Therefore, we derive the public key from the // private key just to satisfy `ssh-keygen` until the problem has been // resolved. // https://github.com/renovatebot/renovate/issues/18197#issuecomment-2152333710 const { stdout } = await (0, exec_1.exec)(`ssh-keygen -y -P "" -f ${keyFileName}`); const pubFileName = `${keyFileName}.pub`; await fs_extra_1.default.outputFile(pubFileName, stdout); process.on('exit', () => fs_extra_1.default.removeSync(pubFileName)); return keyFileName; } async hasPassphrase(keyFileName) { try { await (0, exec_1.exec)(`ssh-keygen -y -P "" -f ${keyFileName}`); } catch (err) { return err.stderr.includes('incorrect passphrase supplied to decrypt private key'); } return false; } } function getPrivateKeyFormat(key) { return sshKeyRegex.test(key) ? 'ssh' : 'gpg'; } function createPrivateKey(key) { switch (getPrivateKeyFormat(key)) { case 'gpg': logger_1.logger.debug('gitPrivateKey: GPG key detected'); return new GPGKey(key); case 'ssh': logger_1.logger.debug('gitPrivateKey: SSH key detected'); return new SSHKey(key); } } function setPrivateKey(key) { if (!is_1.default.nonEmptyStringAndNotWhitespace(key)) { return; } gitPrivateKey = createPrivateKey(key); } async function writePrivateKey() { await gitPrivateKey?.writeKey(); } async function configSigningKey(cwd) { await gitPrivateKey?.configSigningKey(cwd); } //# sourceMappingURL=private-key.js.map