Skip to content

Commit

Permalink
Handle signing-only subkeys
Browse files Browse the repository at this point in the history
  • Loading branch information
crazy-max committed Sep 24, 2021
1 parent 1fb7d85 commit e17b0af
Show file tree
Hide file tree
Showing 17 changed files with 270 additions and 172 deletions.
24 changes: 19 additions & 5 deletions .github/workflows/ci.yml
Expand Up @@ -2,7 +2,7 @@ name: ci

on:
schedule:
- cron: '0 10 * * *' # everyday at 10am
- cron: '0 10 * * *'
push:
branches:
- 'master'
Expand All @@ -20,13 +20,19 @@ jobs:
strategy:
fail-fast: false
matrix:
key:
- test-key
- test-subkey
global:
- false
- true
os:
- ubuntu-latest
- macOS-latest
- windows-latest
include:
- key: test-subkey
fingerprint: C17D11ADF199F12A30A0910F1F80449BE0B08CB8
steps:
-
name: Checkout
Expand All @@ -38,8 +44,8 @@ jobs:
with:
script: |
const fs = require('fs');
core.setOutput('pgp', fs.readFileSync('.github/test-key.pgp', {encoding: 'utf8'}));
core.setOutput('passphrase', fs.readFileSync('.github/test-key.pass', {encoding: 'utf8'}));
core.setOutput('pgp', fs.readFileSync('__tests__/fixtures/${{ matrix.key }}.pgp', {encoding: 'utf8'}));
core.setOutput('passphrase', fs.readFileSync('__tests__/fixtures/${{ matrix.key }}.pass', {encoding: 'utf8'}));
-
name: Import GPG
id: import_gpg
Expand All @@ -52,6 +58,7 @@ jobs:
git_commit_gpgsign: true
git_tag_gpgsign: true
git_push_gpgsign: if-asked
fingerprint: ${{ matrix.fingerprint }}
-
name: GPG user IDs
run: |
Expand All @@ -65,10 +72,16 @@ jobs:
strategy:
fail-fast: false
matrix:
key:
- test-key
- test-subkey
os:
- ubuntu-latest
- macOS-latest
- windows-latest
include:
- key: test-subkey
fingerprint: C17D11ADF199F12A30A0910F1F80449BE0B08CB8
steps:
-
name: Checkout
Expand All @@ -80,8 +93,8 @@ jobs:
with:
script: |
const fs = require('fs');
core.setOutput('pgp-base64', fs.readFileSync('.github/test-key-base64.pgp', {encoding: 'utf8'}));
core.setOutput('passphrase', fs.readFileSync('.github/test-key.pass', {encoding: 'utf8'}));
core.setOutput('pgp-base64', fs.readFileSync('__tests__/fixtures/${{ matrix.key }}-base64.pgp', {encoding: 'utf8'}));
core.setOutput('passphrase', fs.readFileSync('__tests__/fixtures/${{ matrix.key }}.pass', {encoding: 'utf8'}));
-
name: Import GPG
id: import_gpg
Expand All @@ -93,6 +106,7 @@ jobs:
git_commit_gpgsign: true
git_tag_gpgsign: true
git_push_gpgsign: if-asked
fingerprint: ${{ matrix.fingerprint }}
-
name: GPG user IDs
run: |
Expand Down
1 change: 1 addition & 0 deletions README.md
Expand Up @@ -141,6 +141,7 @@ Following inputs can be used as `step.with` keys
| `git_committer_name` | String | Set commit author's name (defaults to the name associated with the GPG key) |
| `git_committer_email` | String | Set commit author's email (defaults to the email address associated with the GPG key) |
| `workdir` | String | Working directory (below repository root) (default `.`) |
| `fingerprint` | String | Specific fingerprint to use (subkey) |

> `git_user_signingkey` needs to be enabled for `git_commit_gpgsign`, `git_tag_gpgsign`,
> `git_push_gpgsign`, `git_committer_name`, `git_committer_email` inputs.
Expand Down
1 change: 0 additions & 1 deletion __tests__/context.test.ts
@@ -1,5 +1,4 @@
import * as os from 'os';

import * as context from '../src/context';

describe('setOutput', () => {
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
1 change: 1 addition & 0 deletions __tests__/fixtures/test-subkey-base64.pgp
@@ -0,0 +1 @@
LS0tLS1CRUdJTiBQR1AgUFJJVkFURSBLRVkgQkxPQ0stLS0tLQoKbElZRVlVNU0yaFlKS3dZQkJBSGFSdzhCQVFkQXNSbDlDUEtaaDB4MC9FRDFveDJwTmJ6R1J1TlpvRlVSN0JsYgpOUUdabzB6K0J3TUN1dVdvaTR5WTQ0YkhNU1AwMjBLRmUvOHhpWHJwby9LandiMXJaa1g3dW1laWZBRFh6L1JiCmJuMXdKMENGQ09TOHl4R3laL3NCYlk1OGZEL0gvMFU2TFdiSmRHSG1mZ0RXYTl0OEFQK09NTFFWU205bElFSmgKY2lBOGFtOWxRR0poY2k1bWIyOCtpSkFFRXhZS0FEZ1dJUVNIOGxlNG5PUmlFQXZzRC81Z2NkSVlPQS9jeUFVQwpZVTVNMmdJYkFRVUxDUWdIQXdVVkNna0lDd1VXQWdNQkFBSWVBUUlYZ0FBS0NSQmdjZElZT0EvY3lGd1VBUUN0CmRQdzU3MDh0Z296NkNqcEFMbzBjQ2NtZ2xuVHdGWlBYTm1DaGdPZUIzQUVBdkdNV2lrYy9iaG9waVRGUzNLVWkKR042a1o5ZUlhaTRYeDloTjRSZTlEd1NjaGdSaFRrMURGZ2tyQmdFRUFkcEhEd0VCQjBDVUtPdVVMYlNqZVF4QwpHNmY4VkhNWHRUbnc4MkF2TmlwM01rY3RNZEZmbC80SEF3SlBPM1loUVJkWU44Y1A1cVhvOFcwazFPZEJaTEJyCmN5cm5ra2tYVk91cjh1SlExV2tMb2FMSnZ3VmN1MlplSFlWdmcramNFSmVlTVF0ME43OWVOUUs5VVMzeEQ5ak4Kc2JZbTVrUkNHWldpaU84RUdCWUtBQ0FXSVFTSDhsZTRuT1JpRUF2c0QvNWdjZElZT0EvY3lBVUNZVTVOUXdJYgpBZ0NCQ1JCZ2NkSVlPQS9jeUhZZ0JCa1dDZ0FkRmlFRXdYMFJyZkdaOFNvd29KRVBINEJFbStDd2pMZ0ZBbUZPClRVTUFDZ2tRSDRCRW0rQ3dqTGlJT1FFQTZjazVCbXMwYzBvbHV4Ly9BeUprMlpINWl5WW11WmpaVTJNOEhtcEoKa1BJQkFPVWJsQmlwZURpc0dqQ0VmTE1SN1czcFBYTTMyY0ZOWVdwOW1SNzJ6SWdOcEdvQS8zM1grRG55VHhtTgpYeUlpZFFtK0J3TFBZOXRTUlMvL0dCbVg4eHdDUWpWS0FRRG54V0VyaVk4clBQOTFUblhtR0VjL05LeFZVcHJoCjVRTndjMHNBTjVGRUJ3PT0KPTExQjQKLS0tLS1FTkQgUEdQIFBSSVZBVEUgS0VZIEJMT0NLLS0tLS0K
1 change: 1 addition & 0 deletions __tests__/fixtures/test-subkey.pass
@@ -0,0 +1 @@
with another passphrase
19 changes: 19 additions & 0 deletions __tests__/fixtures/test-subkey.pgp
@@ -0,0 +1,19 @@
-----BEGIN PGP PRIVATE KEY BLOCK-----

lIYEYU5M2hYJKwYBBAHaRw8BAQdAsRl9CPKZh0x0/ED1ox2pNbzGRuNZoFUR7Blb
NQGZo0z+BwMCuuWoi4yY44bHMSP020KFe/8xiXrpo/Kjwb1rZkX7umeifADXz/Rb
bn1wJ0CFCOS8yxGyZ/sBbY58fD/H/0U6LWbJdGHmfgDWa9t8AP+OMLQVSm9lIEJh
ciA8am9lQGJhci5mb28+iJAEExYKADgWIQSH8le4nORiEAvsD/5gcdIYOA/cyAUC
YU5M2gIbAQULCQgHAwUVCgkICwUWAgMBAAIeAQIXgAAKCRBgcdIYOA/cyFwUAQCt
dPw5708tgoz6CjpALo0cCcmglnTwFZPXNmChgOeB3AEAvGMWikc/bhopiTFS3KUi
GN6kZ9eIai4Xx9hN4Re9DwSchgRhTk1DFgkrBgEEAdpHDwEBB0CUKOuULbSjeQxC
G6f8VHMXtTnw82AvNip3MkctMdFfl/4HAwJPO3YhQRdYN8cP5qXo8W0k1OdBZLBr
cyrnkkkXVOur8uJQ1WkLoaLJvwVcu2ZeHYVvg+jcEJeeMQt0N79eNQK9US3xD9jN
sbYm5kRCGZWiiO8EGBYKACAWIQSH8le4nORiEAvsD/5gcdIYOA/cyAUCYU5NQwIb
AgCBCRBgcdIYOA/cyHYgBBkWCgAdFiEEwX0RrfGZ8SowoJEPH4BEm+CwjLgFAmFO
TUMACgkQH4BEm+CwjLiIOQEA6ck5Bms0c0olux//AyJk2ZH5iyYmuZjZU2M8HmpJ
kPIBAOUblBipeDisGjCEfLMR7W3pPXM32cFNYWp9mR72zIgNpGoA/33X+DnyTxmN
XyIidQm+BwLPY9tSRS//GBmX8xwCQjVKAQDnxWEriY8rPP91TnXmGEc/NKxVUprh
5QNwc0sAN5FEBw==
=11B4
-----END PGP PRIVATE KEY BLOCK-----
187 changes: 106 additions & 81 deletions __tests__/gpg.test.ts
@@ -1,105 +1,130 @@
import * as fs from 'fs';
import * as gpg from '../src/gpg';

const userInfo = {
pgp: fs.readFileSync('.github/test-key.pgp', {
encoding: 'utf8',
flag: 'r'
}),
pgp_base64: fs.readFileSync('.github/test-key-base64.pgp', {
encoding: 'utf8',
flag: 'r'
}),
passphrase: fs.readFileSync('.github/test-key.pass', {
encoding: 'utf8',
flag: 'r'
}),
name: 'Joe Tester',
email: 'joe@foo.bar',
keyID: 'D523BD50DD70B0BA',
fingerprint: '27571A53B86AF0C799B38BA77D851EB72D73BDA0',
keygrips: ['3E2D1142AA59E08E16B7E2C64BA6DDC773B1A627', 'BA83FC8947213477F28ADC019F6564A956456163']
};
const userInfos = [
{
key: 'test-key',
pgp: fs.readFileSync('__tests__/fixtures/test-key.pgp', {
encoding: 'utf8',
flag: 'r'
}),
pgp_base64: fs.readFileSync('__tests__/fixtures/test-key-base64.pgp', {
encoding: 'utf8',
flag: 'r'
}),
passphrase: fs.readFileSync('__tests__/fixtures/test-key.pass', {
encoding: 'utf8',
flag: 'r'
}),
name: 'Joe Tester',
email: 'joe@foo.bar',
keyID: '7D851EB72D73BDA0',
fingerprint: '27571A53B86AF0C799B38BA77D851EB72D73BDA0',
keygrips: ['3E2D1142AA59E08E16B7E2C64BA6DDC773B1A627', 'BA83FC8947213477F28ADC019F6564A956456163']
},
{
key: 'test-subkey',
pgp: fs.readFileSync('__tests__/fixtures/test-subkey.pgp', {
encoding: 'utf8',
flag: 'r'
}),
pgp_base64: fs.readFileSync('__tests__/fixtures/test-subkey-base64.pgp', {
encoding: 'utf8',
flag: 'r'
}),
passphrase: fs.readFileSync('__tests__/fixtures/test-subkey.pass', {
encoding: 'utf8',
flag: 'r'
}),
name: 'Joe Bar',
email: 'joe@bar.foo',
keyID: '6071D218380FDCC8',
fingerprint: 'C17D11ADF199F12A30A0910F1F80449BE0B08CB8',
keygrips: ['F5C3ABFAAB36B427FD98C4EDD0387E08EA1E8092', 'DEE0FC98F441519CA5DE5D79773CB29009695FEB']
}
];

describe('gpg', () => {
describe('getVersion', () => {
it('returns GnuPG and libgcrypt version', async () => {
await gpg.getVersion().then(version => {
console.log(version);
expect(version.gnupg).not.toEqual('');
expect(version.libgcrypt).not.toEqual('');
});
describe('getVersion', () => {
it('returns GnuPG and libgcrypt version', async () => {
await gpg.getVersion().then(version => {
console.log(version);
expect(version.gnupg).not.toEqual('');
expect(version.libgcrypt).not.toEqual('');
});
});
});

describe('getDirs', () => {
it('returns GnuPG dirs', async () => {
await gpg.getDirs().then(dirs => {
console.log(dirs);
expect(dirs.libdir).not.toEqual('');
expect(dirs.datadir).not.toEqual('');
expect(dirs.homedir).not.toEqual('');
});
describe('getDirs', () => {
it('returns GnuPG dirs', async () => {
await gpg.getDirs().then(dirs => {
console.log(dirs);
expect(dirs.libdir).not.toEqual('');
expect(dirs.datadir).not.toEqual('');
expect(dirs.homedir).not.toEqual('');
});
});
});

describe('importKey', () => {
it('imports key (as armored string) to GnuPG', async () => {
await gpg.importKey(userInfo.pgp).then(output => {
console.log(output);
expect(output).not.toEqual('');
});
});
it('imports key (as base64 string) to GnuPG', async () => {
await gpg.importKey(userInfo.pgp_base64).then(output => {
console.log(output);
expect(output).not.toEqual('');
});
});
describe('configureAgent', () => {
it('configures GnuPG agent', async () => {
await gpg.configureAgent(gpg.agentConfig);
});
});

describe('getKeygrips', () => {
it('returns the keygrips', async () => {
await gpg.importKey(userInfo.pgp);
await gpg.getKeygrips(userInfo.fingerprint).then(keygrips => {
console.log(keygrips);
expect(keygrips.length).toEqual(userInfo.keygrips.length);
for (let i = 0; i < keygrips.length; i++) {
expect(keygrips[i]).toEqual(userInfo.keygrips[i]);
}
for (let userInfo of userInfos) {
describe(userInfo.key, () => {
describe('importKey', () => {
it('imports key (as armored string) to GnuPG', async () => {
await gpg.importKey(userInfo.pgp).then(output => {
console.log(output);
expect(output).not.toEqual('');
});
});
it('imports key (as base64 string) to GnuPG', async () => {
await gpg.importKey(userInfo.pgp_base64).then(output => {
console.log(output);
expect(output).not.toEqual('');
});
});
});
});

describe('configureAgent', () => {
it('configures GnuPG agent', async () => {
await gpg.configureAgent(gpg.agentConfig);
describe('getKeygrips', () => {
it('returns the keygrips', async () => {
await gpg.importKey(userInfo.pgp);
await gpg.getKeygrips(userInfo.fingerprint).then(keygrips => {
console.log(keygrips);
expect(keygrips.length).toEqual(userInfo.keygrips.length);
for (let i = 0; i < keygrips.length; i++) {
expect(keygrips[i]).toEqual(userInfo.keygrips[i]);
}
});
});
});
});

describe('presetPassphrase', () => {
it('presets passphrase', async () => {
await gpg.importKey(userInfo.pgp);
await gpg.configureAgent(gpg.agentConfig);
for (let keygrip of await gpg.getKeygrips(userInfo.fingerprint)) {
await gpg.presetPassphrase(keygrip, userInfo.passphrase).then(output => {
console.log(output);
expect(output).not.toEqual('');
});
}
describe('presetPassphrase', () => {
it('presets passphrase', async () => {
await gpg.importKey(userInfo.pgp);
await gpg.configureAgent(gpg.agentConfig);
for (let keygrip of await gpg.getKeygrips(userInfo.fingerprint)) {
await gpg.presetPassphrase(keygrip, userInfo.passphrase).then(output => {
console.log(output);
expect(output).not.toEqual('');
});
}
});
});
});

describe('deleteKey', () => {
it('removes key from GnuPG', async () => {
await gpg.importKey(userInfo.pgp);
await gpg.deleteKey(userInfo.fingerprint);
describe('deleteKey', () => {
it('removes key from GnuPG', async () => {
await gpg.importKey(userInfo.pgp);
await gpg.deleteKey(userInfo.fingerprint);
});
});
});
}

describe('killAgent', () => {
it('kills GnuPG agent', async () => {
await gpg.killAgent();
});
describe('killAgent', () => {
it('kills GnuPG agent', async () => {
await gpg.killAgent();
});
});

0 comments on commit e17b0af

Please sign in to comment.