From 84ca13a8bd73fd30e7ed604cf256be563cbd8eb2 Mon Sep 17 00:00:00 2001 From: Sigurd Spieckermann <2206639+sisp@users.noreply.github.com> Date: Sat, 29 Jun 2024 14:02:26 +0200 Subject: [PATCH] refactor(git): prepare support for commit signing with other key formats (#29875) --- lib/util/git/private-key.ts | 93 +++++++++++++++++++++---------------- 1 file changed, 53 insertions(+), 40 deletions(-) diff --git a/lib/util/git/private-key.ts b/lib/util/git/private-key.ts index 681331d06846e6..dac6bb275d0801 100644 --- a/lib/util/git/private-key.ts +++ b/lib/util/git/private-key.ts @@ -8,56 +8,69 @@ import { exec } from '../exec'; import { newlineRegex } from '../regex'; import { addSecretForSanitizing } from '../sanitize'; -let gitPrivateKey: string | undefined; -let keyId: string | undefined; +let gitPrivateKey: PrivateKey | undefined; -export function setPrivateKey(key: string | undefined): void { - if (!is.nonEmptyStringAndNotWhitespace(key)) { - return; +abstract class PrivateKey { + protected readonly key: string; + protected keyId: string | undefined; + + constructor(key: string) { + this.key = key.trim(); + addSecretForSanitizing(this.key, 'global'); + logger.debug( + 'gitPrivateKey: successfully set (but not yet written/configured)', + ); + } + + async writeKey(): Promise { + try { + if (!this.keyId) { + this.keyId = await this.importKey(); + } + logger.debug('gitPrivateKey: imported'); + } catch (err) { + logger.warn({ err }, 'gitPrivateKey: error importing'); + throw new Error(PLATFORM_GPG_FAILED); + } + } + + async configSigningKey(cwd: string): Promise { + logger.debug('gitPrivateKey: configuring commit signing'); + // TODO: types (#22198) + await exec(`git config user.signingkey ${this.keyId!}`, { cwd }); + await exec(`git config commit.gpgsign true`, { cwd }); } - addSecretForSanitizing(key.trim(), 'global'); - logger.debug( - 'gitPrivateKey: successfully set (but not yet written/configured)', - ); - gitPrivateKey = key.trim(); + + protected abstract importKey(): Promise; } -async function importKey(): Promise { - if (keyId) { - return; +class GPGKey extends PrivateKey { + protected async importKey(): Promise { + const keyFileName = upath.join(os.tmpdir() + '/git-private-gpg.key'); + await fs.outputFile(keyFileName, this.key); + const { stdout, stderr } = await exec(`gpg --import ${keyFileName}`); + logger.debug({ stdout, stderr }, 'Private key import result'); + await fs.remove(keyFileName); + return `${stdout}${stderr}` + .split(newlineRegex) + .find((line) => line.includes('secret key imported')) + ?.replace('gpg: key ', '') + .split(':') + .shift(); } - const keyFileName = upath.join(os.tmpdir() + '/git-private.key'); - await fs.outputFile(keyFileName, gitPrivateKey!); - const { stdout, stderr } = await exec(`gpg --import ${keyFileName}`); - logger.debug({ stdout, stderr }, 'Private key import result'); - keyId = `${stdout}${stderr}` - .split(newlineRegex) - .find((line) => line.includes('secret key imported')) - ?.replace('gpg: key ', '') - .split(':') - .shift(); - await fs.remove(keyFileName); } -export async function writePrivateKey(): Promise { - if (!gitPrivateKey) { +export function setPrivateKey(key: string | undefined): void { + if (!is.nonEmptyStringAndNotWhitespace(key)) { return; } - try { - await importKey(); - logger.debug('gitPrivateKey: imported'); - } catch (err) { - logger.warn({ err }, 'gitPrivateKey: error importing'); - throw new Error(PLATFORM_GPG_FAILED); - } + gitPrivateKey = new GPGKey(key); +} + +export async function writePrivateKey(): Promise { + await gitPrivateKey?.writeKey(); } export async function configSigningKey(cwd: string): Promise { - if (!gitPrivateKey) { - return; - } - logger.debug('gitPrivateKey: configuring commit signing'); - // TODO: types (#22198) - await exec(`git config user.signingkey ${keyId!}`, { cwd }); - await exec(`git config commit.gpgsign true`, { cwd }); + await gitPrivateKey?.configSigningKey(cwd); }