diff --git a/README.md b/README.md
index 6d0a36b..ea551b8 100644
--- a/README.md
+++ b/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.
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
diff --git a/__tests__/openpgp.test.ts b/__tests__/openpgp.test.ts
index 565c8c9..86e01fb 100644
--- a/__tests__/openpgp.test.ts
+++ b/__tests__/openpgp.test.ts
@@ -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();
diff --git a/action.yml b/action.yml
index c9e89a7..8dec262 100644
--- a/action.yml
+++ b/action.yml
@@ -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'
diff --git a/src/main.ts b/src/main.ts
index 591f23b..c4449f0 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -28,8 +28,10 @@ async function run(): Promise {
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 {
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;
}
diff --git a/src/openpgp.ts b/src/openpgp.ts
index 91908ef..d3a382f 100644
--- a/src/openpgp.ts
+++ b/src/openpgp.ts
@@ -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 => {
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()
};
};