Skip to content

Commit f6dda1c

Browse files
authored
fix(git-node): check the tag signature and not the commit one (#907)
During release promotion, we want to verify the tag is signed with one of the releasers' key. The commit can be signed with a different signature (e.g. the bot's, or a soon-to-be releaser).
1 parent 021161b commit f6dda1c

File tree

2 files changed

+34
-16
lines changed

2 files changed

+34
-16
lines changed

lib/promote_release.js

+20-13
Original file line numberDiff line numberDiff line change
@@ -226,20 +226,28 @@ export default class ReleasePromotion extends Session {
226226

227227
async verifyTagSignature() {
228228
const { cli, version } = this;
229-
const [needle, haystack] = await Promise.all([forceRunAsync(
229+
const verifyTagPattern = /gpg:[^\n]+\ngpg:\s+using RSA key ([^\n]+)\ngpg:\s+issuer "([^"]+)"\ngpg:\s+Good signature from "([^<]+) <\2>"/;
230+
const [verifyTagOutput, haystack] = await Promise.all([forceRunAsync(
230231
'git', ['--no-pager',
231-
'log', '-1',
232-
`refs/tags/v${version}`,
233-
'--format=* **%an** <<%ae>>\n `%GF`'
234-
], { captureStdout: true }), fs.readFile('README.md')]);
235-
if (haystack.includes(needle)) {
236-
return;
232+
'verify-tag',
233+
`v${version}`
234+
], { ignoreFailure: false, captureStderr: true }), fs.readFile('README.md')]);
235+
const match = verifyTagPattern.exec(verifyTagOutput);
236+
if (match == null) {
237+
cli.warn('git was not able to verify the tag:');
238+
cli.info(verifyTagOutput);
239+
} else {
240+
const [, keyID, email, name] = match;
241+
const needle = `* **${name}** <<${email}>>\n ${'`'}${keyID}${'`'}`;
242+
if (haystack.includes(needle)) {
243+
return;
244+
}
245+
cli.warn('Tag was signed with an undocumented identity/key pair!');
246+
cli.info('Expected to find the following entry in the README:');
247+
cli.info(needle);
248+
cli.info('If you are using a subkey, it might be OK.');
237249
}
238-
cli.warn('Tag was signed with an undocumented identity/key pair!');
239-
cli.info('Expected to find the following entry in the README:');
240-
cli.info(needle);
241-
cli.info('If you are using a subkey, it might be OK.');
242-
cli.info(`Otherwise consider removing the tag (git tag -d v${version
250+
cli.info(`If that doesn't sound right, consider removing the tag (git tag -d v${version
243251
}), check your local config, and start the process over.`);
244252
if (!await cli.prompt('Do you want to proceed anyway?', { defaultAnswer: false })) {
245253
throw new Error('Aborted');
@@ -383,7 +391,6 @@ export default class ReleasePromotion extends Session {
383391
{ cause: err }
384392
);
385393
}
386-
await forceRunAsync('git', ['tag', '--verify', `v${version}`], { ignoreFailure: false });
387394
this.cli.info('Using the existing tag');
388395
}
389396
}

lib/run.js

+14-3
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,19 @@ function runAsyncBase(cmd, args, {
1212
ignoreFailure = true,
1313
spawnArgs,
1414
input,
15+
captureStderr = false,
1516
captureStdout = false
1617
} = {}) {
1718
if (cmd instanceof URL) {
1819
cmd = fileURLToPath(cmd);
1920
}
2021
let stdio = 'inherit';
21-
if (captureStdout || input != null) {
22-
stdio = [input == null ? 'inherit' : 'pipe', captureStdout ? 'pipe' : 'inherit', 'inherit'];
22+
if (captureStderr || captureStdout || input != null) {
23+
stdio = [
24+
input == null ? 'inherit' : 'pipe',
25+
captureStdout ? 'pipe' : 'inherit',
26+
captureStderr ? 'pipe' : 'inherit'
27+
];
2328
}
2429
return new Promise((resolve, reject) => {
2530
const opt = Object.assign({
@@ -30,6 +35,12 @@ function runAsyncBase(cmd, args, {
3035
debuglog('[Spawn]', `${cmd} ${(args || []).join(' ')}`, opt);
3136
}
3237
const child = spawn(cmd, args, opt);
38+
let stderr;
39+
if (!captureStdout && captureStderr) {
40+
stderr = '';
41+
child.stderr.setEncoding('utf8');
42+
child.stderr.on('data', (chunk) => { stderr += chunk; });
43+
}
3344
let stdout;
3445
if (captureStdout) {
3546
stdout = '';
@@ -51,7 +62,7 @@ function runAsyncBase(cmd, args, {
5162
stdout = stdout.split(/\r?\n/g);
5263
if (stdout[stdout.length - 1] === '') stdout.pop();
5364
}
54-
return resolve(stdout);
65+
return resolve(stdout ?? stderr);
5566
});
5667
if (input != null) child.stdin.end(input);
5768
});

0 commit comments

Comments
 (0)