Skip to content

Commit

Permalink
Allow to seed the internal cache of gpg-agent with provided passphrase (
Browse files Browse the repository at this point in the history
#5)

Better handling of commands output streams
  • Loading branch information
crazy-max committed May 4, 2020
1 parent 9a41db0 commit a8f7b59
Show file tree
Hide file tree
Showing 8 changed files with 1,611 additions and 75 deletions.
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,4 @@ jobs:
uses: ./
env:
SIGNING_KEY: ${{ secrets.SIGNING_KEY_TEST }}
PASSPHRASE: ${{ secrets.PASSPHRASE_TEST }}
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ If you are interested, [check out](https://git.io/Je09Y) my other :octocat: GitH

![Import GPG key](.res/ghaction-import-gpg.png)

## Features

* Works on Linux, MacOS and Windows [virtual environments](https://help.github.com/en/articles/virtual-environments-for-github-actions#supported-virtual-environments-and-hardware-resources)
* Allow to seed the internal cache of `gpg-agent` with provided passphrase
* Purge imported GPG key and cache information from runner (security)

## Usage

```yaml
Expand All @@ -33,6 +39,7 @@ jobs:
uses: crazy-max/ghaction-import-gpg@master
env:
SIGNING_KEY: ${{ secrets.SIGNING_KEY }}
PASSPHRASE: ${{ secrets.PASSPHRASE }}
```
## Customizing
Expand All @@ -44,6 +51,7 @@ Following environment variables can be used as `step.env` keys
| Name | Description |
|----------------|---------------------------------------|
| `SIGNING_KEY` | GPG private key exported as an ASCII armored version |
| `PASSPHRASE` | Passphrase of your GPG key if setted for your `SIGNING_KEY` |

## How can I help?

Expand Down
61 changes: 47 additions & 14 deletions __tests__/gpg.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import {deleteKey, getVersion, importKey} from '../src/gpg';
import * as child_process from 'child_process';
import * as gpg from '../src/gpg';

const userInfo = {
name: 'Joe Tester',
Expand All @@ -8,6 +7,7 @@ const userInfo = {
keyID: 'D523BD50DD70B0BA',
userID: 'Joe Tester <[email protected]>',
fingerprint: '27571A53B86AF0C799B38BA77D851EB72D73BDA0',
keygrip: 'BA83FC8947213477F28ADC019F6564A956456163',
pgp: `-----BEGIN PGP PRIVATE KEY BLOCK-----
lQdGBF6tzaABEACjFbX7PFEG6vDPN2MPyxYW7/3o/sonORj4HXUFjFxxJxktJ3x3
Expand Down Expand Up @@ -119,33 +119,66 @@ PejgXO0uIRolYQ3sz2tMGhx1MfBqH64=
describe('gpg', () => {
describe('getVersion', () => {
it('returns GnuPG and libgcrypt version', async () => {
await getVersion().then(version => {
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('importKey', () => {
it('imports key to GnuPG', async () => {
await importKey(userInfo.pgp).then(() => {
console.log(
child_process.execSync(`gpg --batch --list-keys --keyid-format LONG ${userInfo.email}`, {encoding: 'utf8'})
);
console.log(
child_process.execSync(`gpg --batch --list-secret-keys --keyid-format LONG ${userInfo.email}`, {
encoding: 'utf8'
})
);
await gpg.importKey(userInfo.pgp).then(output => {
console.log(output);
expect(output).not.toEqual('');
});
});
});

describe('getKeygrip', () => {
it('returns the keygrip', async () => {
await gpg.importKey(userInfo.pgp);
await gpg.getKeygrip(userInfo.fingerprint).then(keygrip => {
console.log(keygrip);
expect(keygrip).toEqual(userInfo.keygrip);
});
});
});

describe('configureAgent', () => {
it('configures GnuPG agent', async () => {
await gpg.configureAgent(gpg.agentConfig);
});
});

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

describe('deleteKey', () => {
it('removes key from GnuPG', async () => {
await importKey(userInfo.pgp);
await deleteKey(userInfo.fingerprint);
await gpg.importKey(userInfo.pgp);
await gpg.deleteKey(userInfo.fingerprint);
});
});
});
6 changes: 3 additions & 3 deletions __tests__/openpgp.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {readPrivateKey, generateKeyPair} from '../src/openpgp';
import * as openpgp from '../src/openpgp';

const userInfo = {
name: 'Joe Tester',
Expand Down Expand Up @@ -118,7 +118,7 @@ PejgXO0uIRolYQ3sz2tMGhx1MfBqH64=
describe('openpgp', () => {
describe('readPrivateKey', () => {
it('returns a PGP private key', async () => {
await readPrivateKey(userInfo.pgp).then(privateKey => {
await openpgp.readPrivateKey(userInfo.pgp).then(privateKey => {
expect(privateKey.keyID).toEqual(userInfo.keyID);
expect(privateKey.userID).toEqual(userInfo.userID);
expect(privateKey.fingerprint).toEqual(userInfo.fingerprint);
Expand All @@ -128,7 +128,7 @@ describe('openpgp', () => {

describe('generateKeyPair', () => {
it('generates a PGP key pair', async () => {
await generateKeyPair(userInfo.name, userInfo.email, userInfo.passphrase).then(keyPair => {
await openpgp.generateKeyPair(userInfo.name, userInfo.email, userInfo.passphrase).then(keyPair => {
expect(keyPair).not.toBeUndefined();
expect(keyPair.publicKey).not.toBeUndefined();
expect(keyPair.privateKey).not.toBeUndefined();
Expand Down
Loading

0 comments on commit a8f7b59

Please sign in to comment.