Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(git): prepare support for commit signing with other key formats #29875

Merged
merged 1 commit into from
Jun 29, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 53 additions & 40 deletions lib/util/git/private-key.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<void> {
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<void> {
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<string | undefined>;
}

async function importKey(): Promise<void> {
if (keyId) {
return;
class GPGKey extends PrivateKey {
protected async importKey(): Promise<string | undefined> {
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<void> {
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<void> {
await gitPrivateKey?.writeKey();
}

export async function configSigningKey(cwd: string): Promise<void> {
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);
}