mirror of
https://github.com/crazy-max/ghaction-import-gpg.git
synced 2024-11-25 22:41:04 -05:00
Allow using any user id of the key's user ids as committer identity. Fixes #156
This commit is contained in:
parent
78fb6ec0e4
commit
5170336089
5 changed files with 73 additions and 33 deletions
13
README.md
13
README.md
|
@ -229,12 +229,13 @@ The following inputs can be used as `step.with` keys
|
|||
|
||||
Following outputs are available
|
||||
|
||||
| Name | Type | Description |
|
||||
|---------------|--------|---------------------------------------------------------------------------------------------------------------------------------|
|
||||
| `fingerprint` | String | Fingerprint of the GPG key (recommended as [user ID](https://www.gnupg.org/documentation/manuals/gnupg/Specify-a-User-ID.html)) |
|
||||
| `keyid` | String | Low 64 bits of the X.509 certificate SHA-1 fingerprint |
|
||||
| `name` | String | Name associated with the GPG key |
|
||||
| `email` | String | Email address associated with the GPG key |
|
||||
| Name | Type | Description |
|
||||
|---------------|---------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| `fingerprint` | String | Fingerprint of the GPG key (recommended as [user ID](https://www.gnupg.org/documentation/manuals/gnupg/Specify-a-User-ID.html)) |
|
||||
| `keyid` | String | Low 64 bits of the X.509 certificate SHA-1 fingerprint |
|
||||
| `name` | String | Primary name associated with the GPG key |
|
||||
| `email` | String | Primary email address associated with the GPG key |
|
||||
| `userids` | String (JSON) | All user ids (including primary) associated with the GPG Key.<br/>The output is a JSON array where each object has a `name` and `email` key. Use [fromJson](https://docs.github.com/en/actions/learn-github-actions/expressions#fromjson) to turn the String back into a JSON array |
|
||||
|
||||
## Contributing
|
||||
|
||||
|
|
|
@ -17,8 +17,16 @@ const userInfos = [
|
|||
encoding: 'utf8',
|
||||
flag: 'r'
|
||||
}),
|
||||
name: 'Joe Tester',
|
||||
email: 'joe@foo.bar',
|
||||
primaryUserId: {
|
||||
name: 'Joe Tester',
|
||||
email: 'joe@foo.bar'
|
||||
},
|
||||
userIds: [
|
||||
{
|
||||
name: 'Joe Tester',
|
||||
email: 'joe@foo.bar'
|
||||
}
|
||||
],
|
||||
keyID: '7D851EB72D73BDA0',
|
||||
fingerprint: '27571A53B86AF0C799B38BA77D851EB72D73BDA0',
|
||||
keygrip: '3E2D1142AA59E08E16B7E2C64BA6DDC773B1A627'
|
||||
|
@ -37,8 +45,16 @@ const userInfos = [
|
|||
encoding: 'utf8',
|
||||
flag: 'r'
|
||||
}),
|
||||
name: 'Joe Bar',
|
||||
email: 'joe@bar.foo',
|
||||
primaryUserId: {
|
||||
name: 'Joe Bar',
|
||||
email: 'joe@bar.foo'
|
||||
},
|
||||
userIds: [
|
||||
{
|
||||
name: 'Joe Bar',
|
||||
email: 'joe@bar.foo'
|
||||
}
|
||||
],
|
||||
keyID: '6071D218380FDCC8',
|
||||
fingerprint: '87F257B89CE462100BEC0FFE6071D218380FDCC8',
|
||||
keygrips: ['F5C3ABFAAB36B427FD98C4EDD0387E08EA1E8092', 'DEE0FC98F441519CA5DE5D79773CB29009695FEB']
|
||||
|
@ -52,16 +68,22 @@ for (const userInfo of userInfos) {
|
|||
it('returns a PGP private key from an armored string', async () => {
|
||||
await openpgp.readPrivateKey(userInfo.pgp).then(privateKey => {
|
||||
expect(privateKey.keyID).toEqual(userInfo.keyID);
|
||||
expect(privateKey.name).toEqual(userInfo.name);
|
||||
expect(privateKey.email).toEqual(userInfo.email);
|
||||
expect(privateKey.primaryUserId.name).toEqual(userInfo.primaryUserId.name);
|
||||
expect(privateKey.primaryUserId.email).toEqual(userInfo.primaryUserId.email);
|
||||
expect(privateKey.allUserIds).toHaveLength(userInfo.userIds.length);
|
||||
expect(privateKey.allUserIds[0].name).toEqual(userInfo.userIds[0].name);
|
||||
expect(privateKey.allUserIds[0].email).toEqual(userInfo.userIds[0].email);
|
||||
expect(privateKey.fingerprint).toEqual(userInfo.fingerprint);
|
||||
});
|
||||
});
|
||||
it('returns a PGP private key from a base64 armored string', async () => {
|
||||
await openpgp.readPrivateKey(userInfo.pgp_base64).then(privateKey => {
|
||||
expect(privateKey.keyID).toEqual(userInfo.keyID);
|
||||
expect(privateKey.name).toEqual(userInfo.name);
|
||||
expect(privateKey.email).toEqual(userInfo.email);
|
||||
expect(privateKey.primaryUserId.name).toEqual(userInfo.primaryUserId.name);
|
||||
expect(privateKey.primaryUserId.email).toEqual(userInfo.primaryUserId.email);
|
||||
expect(privateKey.allUserIds).toHaveLength(userInfo.userIds.length);
|
||||
expect(privateKey.allUserIds[0].name).toEqual(userInfo.userIds[0].name);
|
||||
expect(privateKey.allUserIds[0].email).toEqual(userInfo.userIds[0].email);
|
||||
expect(privateKey.fingerprint).toEqual(userInfo.fingerprint);
|
||||
});
|
||||
});
|
||||
|
@ -69,7 +91,7 @@ for (const userInfo of userInfos) {
|
|||
|
||||
describe('generateKeyPair', () => {
|
||||
it('generates a PGP key pair', async () => {
|
||||
await openpgp.generateKeyPair(userInfo.name, userInfo.email, userInfo.passphrase).then(keyPair => {
|
||||
await openpgp.generateKeyPair(userInfo.primaryUserId.name, userInfo.primaryUserId.email, userInfo.passphrase).then(keyPair => {
|
||||
expect(keyPair).not.toBeUndefined();
|
||||
expect(keyPair.publicKey).not.toBeUndefined();
|
||||
expect(keyPair.privateKey).not.toBeUndefined();
|
||||
|
|
|
@ -56,9 +56,11 @@ outputs:
|
|||
keyid:
|
||||
description: 'Low 64 bits of the X.509 certificate SHA-1 fingerprint'
|
||||
name:
|
||||
description: 'Name associated with the GPG key'
|
||||
description: 'Primary name associated with the GPG key'
|
||||
email:
|
||||
description: 'Email address associated with the GPG key'
|
||||
description: 'Primary email address associated with the GPG key'
|
||||
userids:
|
||||
description: 'All user ids (including primary) associated with the GPG Key'
|
||||
|
||||
runs:
|
||||
using: 'node20'
|
||||
|
|
25
src/main.ts
25
src/main.ts
|
@ -28,8 +28,10 @@ async function run(): Promise<void> {
|
|||
await core.group(`GPG private key info`, async () => {
|
||||
core.info(`Fingerprint : ${privateKey.fingerprint}`);
|
||||
core.info(`KeyID : ${privateKey.keyID}`);
|
||||
core.info(`Name : ${privateKey.name}`);
|
||||
core.info(`Email : ${privateKey.email}`);
|
||||
for (const userId of privateKey.allUserIds) {
|
||||
const isPrimary = userId.email === privateKey.primaryUserId.email;
|
||||
core.info(`User ID : ${userId.name} <${userId.email}>${isPrimary ? ' (primary)' : ''}`);
|
||||
}
|
||||
core.info(`CreationTime : ${privateKey.creationTime}`);
|
||||
});
|
||||
|
||||
|
@ -91,21 +93,24 @@ async function run(): Promise<void> {
|
|||
core.setOutput('fingerprint', fingerprint);
|
||||
core.info(`keyid=${privateKey.keyID}`);
|
||||
core.setOutput('keyid', privateKey.keyID);
|
||||
core.info(`name=${privateKey.name}`);
|
||||
core.setOutput('name', privateKey.name);
|
||||
core.info(`email=${privateKey.email}`);
|
||||
core.setOutput('email', privateKey.email);
|
||||
core.info(`name=${privateKey.primaryUserId.name}`);
|
||||
core.setOutput('name', privateKey.primaryUserId.name);
|
||||
core.info(`email=${privateKey.primaryUserId.email}`);
|
||||
core.setOutput('email', privateKey.primaryUserId.email);
|
||||
core.info(`userids=${JSON.stringify(privateKey.allUserIds)}`);
|
||||
core.setOutput('userids', privateKey.allUserIds);
|
||||
});
|
||||
|
||||
if (inputs.gitUserSigningkey) {
|
||||
core.info('Setting GPG signing keyID for this Git repository');
|
||||
await git.setConfig('user.signingkey', privateKey.keyID, inputs.gitConfigGlobal);
|
||||
|
||||
const userEmail = inputs.gitCommitterEmail || privateKey.email;
|
||||
const userName = inputs.gitCommitterName || privateKey.name;
|
||||
const userName = inputs.gitCommitterName || privateKey.primaryUserId.name;
|
||||
const userEmail = inputs.gitCommitterEmail || privateKey.primaryUserId.email;
|
||||
|
||||
if (userEmail != privateKey.email) {
|
||||
core.setFailed(`Committer email "${inputs.gitCommitterEmail}" (name: "${inputs.gitCommitterName}") does not match GPG private key email "${privateKey.email}" (name: "${privateKey.name}")`);
|
||||
if (!privateKey.allUserIds.some(id => id.email === userEmail)) {
|
||||
const keyIdentities = privateKey.allUserIds.map(id => `"${id.email}" (name: "${id.name}")`).join(', ');
|
||||
core.setFailed(`Committer email "${inputs.gitCommitterEmail}" (name: "${inputs.gitCommitterName}") does not match GPG any of the private key user id email addresses: ${keyIdentities}`);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,11 +1,16 @@
|
|||
import * as openpgp from 'openpgp';
|
||||
import addressparser from 'addressparser';
|
||||
|
||||
export interface UserId {
|
||||
name: string;
|
||||
email: string;
|
||||
}
|
||||
|
||||
export interface PrivateKey {
|
||||
fingerprint: string;
|
||||
keyID: string;
|
||||
name: string;
|
||||
email: string;
|
||||
primaryUserId: UserId;
|
||||
allUserIds: UserId[];
|
||||
creationTime: Date;
|
||||
}
|
||||
|
||||
|
@ -19,15 +24,20 @@ export const readPrivateKey = async (key: string): Promise<PrivateKey> => {
|
|||
armoredKey: (await isArmored(key)) ? key : Buffer.from(key, 'base64').toString()
|
||||
});
|
||||
|
||||
const address = await privateKey.getPrimaryUser().then(primaryUser => {
|
||||
return addressparser(primaryUser.user.userID?.userID)[0];
|
||||
const primaryUserId: UserId = await privateKey.getPrimaryUser().then(primaryUser => {
|
||||
const address = addressparser(primaryUser.user.userID?.userID)[0];
|
||||
return {name: address.name, email: address.address};
|
||||
});
|
||||
const allUserIds: UserId[] = privateKey.getUserIDs().map(userId => {
|
||||
const address = addressparser(userId)[0];
|
||||
return {name: address.name, email: address.address};
|
||||
});
|
||||
|
||||
return {
|
||||
fingerprint: privateKey.getFingerprint().toUpperCase(),
|
||||
keyID: privateKey.getKeyID().toHex().toUpperCase(),
|
||||
name: address.name,
|
||||
email: address.address,
|
||||
primaryUserId: primaryUserId,
|
||||
allUserIds: allUserIds,
|
||||
creationTime: privateKey.getCreationTime()
|
||||
};
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue