mirror of
https://github.com/crazy-max/ghaction-import-gpg.git
synced 2024-11-24 22:11:02 -05:00
Merge pull request #168 from crazy-max/trust-input
input to set private key trust level
This commit is contained in:
commit
72b6676b71
9 changed files with 160 additions and 28 deletions
63
.github/workflows/ci.yml
vendored
63
.github/workflows/ci.yml
vendored
|
@ -55,6 +55,7 @@ jobs:
|
|||
if (!fs.existsSync(gnupgfolder)){
|
||||
fs.mkdirSync(gnupgfolder);
|
||||
}
|
||||
fs.chmodSync(gnupgfolder, '0700');
|
||||
fs.copyFile('__tests__/fixtures/gpg.conf', `${gnupgfolder}/gpg.conf`, (err) => {
|
||||
if (err) throw err;
|
||||
});
|
||||
|
@ -69,11 +70,11 @@ jobs:
|
|||
core.setOutput('passphrase', fs.readFileSync('__tests__/fixtures/${{ matrix.key }}.pass', {encoding: 'utf8'}));
|
||||
-
|
||||
name: Import GPG
|
||||
id: import_gpg
|
||||
uses: ./
|
||||
with:
|
||||
gpg_private_key: ${{ steps.test.outputs.pgp }}
|
||||
passphrase: ${{ steps.test.outputs.passphrase }}
|
||||
trust_level: 5
|
||||
git_config_global: ${{ matrix.global }}
|
||||
git_user_signingkey: true
|
||||
git_commit_gpgsign: true
|
||||
|
@ -116,7 +117,6 @@ jobs:
|
|||
core.setOutput('passphrase', fs.readFileSync('__tests__/fixtures/${{ matrix.key }}.pass', {encoding: 'utf8'}));
|
||||
-
|
||||
name: Import GPG
|
||||
id: import_gpg
|
||||
uses: ./
|
||||
with:
|
||||
gpg_private_key: ${{ steps.test.outputs.pgp-base64 }}
|
||||
|
@ -126,3 +126,62 @@ jobs:
|
|||
git_tag_gpgsign: true
|
||||
git_push_gpgsign: if-asked
|
||||
fingerprint: ${{ matrix.fingerprint }}
|
||||
|
||||
trust:
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
key:
|
||||
- test-key
|
||||
level:
|
||||
- ''
|
||||
- 5
|
||||
- 4
|
||||
- 3
|
||||
- 2
|
||||
- 1
|
||||
os:
|
||||
- ubuntu-latest
|
||||
- macOS-latest
|
||||
- windows-latest
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
-
|
||||
name: GPG conf
|
||||
uses: actions/github-script@v6
|
||||
with:
|
||||
script: |
|
||||
const fs = require('fs');
|
||||
const gnupgfolder = `${require('os').homedir()}/.gnupg`;
|
||||
if (!fs.existsSync(gnupgfolder)){
|
||||
fs.mkdirSync(gnupgfolder);
|
||||
}
|
||||
fs.chmodSync(gnupgfolder, '0700');
|
||||
fs.copyFile('__tests__/fixtures/gpg.conf', `${gnupgfolder}/gpg.conf`, (err) => {
|
||||
if (err) throw err;
|
||||
});
|
||||
-
|
||||
name: Get test key and passphrase
|
||||
uses: actions/github-script@v6
|
||||
id: test
|
||||
with:
|
||||
script: |
|
||||
const fs = require('fs');
|
||||
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
|
||||
uses: ./
|
||||
with:
|
||||
gpg_private_key: ${{ steps.test.outputs.pgp }}
|
||||
passphrase: ${{ steps.test.outputs.passphrase }}
|
||||
trust_level: ${{ matrix.level }}
|
||||
-
|
||||
name: List trust values
|
||||
run: |
|
||||
gpg --export-ownertrust
|
||||
shell: bash
|
||||
|
|
78
README.md
78
README.md
|
@ -19,6 +19,7 @@ ___
|
|||
* [Workflow](#workflow)
|
||||
* [Sign commits](#sign-commits)
|
||||
* [Use a subkey](#use-a-subkey)
|
||||
* [Set key's trust level](#set-keys-trust-level)
|
||||
* [Customizing](#customizing)
|
||||
* [inputs](#inputs)
|
||||
* [outputs](#outputs)
|
||||
|
@ -76,7 +77,6 @@ jobs:
|
|||
uses: actions/checkout@v3
|
||||
-
|
||||
name: Import GPG key
|
||||
id: import_gpg
|
||||
uses: crazy-max/ghaction-import-gpg@v5
|
||||
with:
|
||||
gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }}
|
||||
|
@ -139,7 +139,6 @@ jobs:
|
|||
uses: actions/checkout@v3
|
||||
-
|
||||
name: Import GPG key
|
||||
id: import_gpg
|
||||
uses: crazy-max/ghaction-import-gpg@v5
|
||||
with:
|
||||
gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }}
|
||||
|
@ -164,26 +163,63 @@ sub ed25519 2021-09-24 [S]
|
|||
|
||||
You can use the subkey with signing capability whose fingerprint is `C17D11ADF199F12A30A0910F1F80449BE0B08CB8`.
|
||||
|
||||
### Set key's trust level
|
||||
|
||||
With the `trust_level` input, you can specify the trust level of the GPG key.
|
||||
|
||||
Valid values are:
|
||||
* `1`: unknown
|
||||
* `2`: never
|
||||
* `3`: marginal
|
||||
* `4`: full
|
||||
* `5`: ultimate
|
||||
|
||||
```yaml
|
||||
name: import-gpg
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: master
|
||||
|
||||
jobs:
|
||||
import-gpg:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
-
|
||||
name: Import GPG key
|
||||
uses: crazy-max/ghaction-import-gpg@v5
|
||||
with:
|
||||
gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }}
|
||||
passphrase: ${{ secrets.PASSPHRASE }}
|
||||
trust_level: 5
|
||||
```
|
||||
|
||||
## Customizing
|
||||
|
||||
### inputs
|
||||
|
||||
Following inputs can be used as `step.with` keys
|
||||
|
||||
| Name | Type | Description |
|
||||
|---------------------------------------|---------|------------------------------------------------|
|
||||
| `gpg_private_key` | String | GPG private key exported as an ASCII armored version or its base64 encoding (**required**) |
|
||||
| `passphrase` | String | Passphrase of the GPG private key |
|
||||
| `git_config_global` | Bool | Set Git config global (default `false`) |
|
||||
| `git_user_signingkey` | Bool | Set GPG signing keyID for this Git repository (default `false`) |
|
||||
| `git_commit_gpgsign` | Bool | Sign all commits automatically. (default `false`) |
|
||||
| `git_tag_gpgsign` | Bool | Sign all tags automatically. (default `false`) |
|
||||
| `git_push_gpgsign` | String | Sign all pushes automatically. (default `if-asked`) |
|
||||
| `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) |
|
||||
| Name | Type | Description |
|
||||
|-----------------------|--------|--------------------------------------------------------------------------------------------|
|
||||
| `gpg_private_key` | String | GPG private key exported as an ASCII armored version or its base64 encoding (**required**) |
|
||||
| `passphrase` | String | Passphrase of the GPG private key |
|
||||
| `trust_level` | String | Set key's trust level |
|
||||
| `git_config_global` | Bool | Set Git config global (default `false`) |
|
||||
| `git_user_signingkey` | Bool | Set GPG signing keyID for this Git repository (default `false`) |
|
||||
| `git_commit_gpgsign` | Bool | Sign all commits automatically. (default `false`) |
|
||||
| `git_tag_gpgsign` | Bool | Sign all tags automatically. (default `false`) |
|
||||
| `git_push_gpgsign` | String | Sign all pushes automatically. (default `if-asked`) |
|
||||
| `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) |
|
||||
|
||||
> **Note**
|
||||
>
|
||||
> `git_user_signingkey` needs to be enabled for `git_commit_gpgsign`, `git_tag_gpgsign`,
|
||||
> `git_push_gpgsign`, `git_committer_name`, `git_committer_email` inputs.
|
||||
|
||||
|
@ -191,12 +227,12 @@ 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 | Name associated with the GPG key |
|
||||
| `email` | String | Email address associated with the GPG key |
|
||||
|
||||
## Contributing
|
||||
|
||||
|
|
|
@ -107,10 +107,10 @@ for (const userInfo of userInfos) {
|
|||
describe('getKeygrip', () => {
|
||||
it('returns the keygrip for a given fingerprint', async () => {
|
||||
await gpg.importKey(userInfo.pgp);
|
||||
for (const [i, fingerprint] of userInfo.fingerprints.entries()) {
|
||||
for (const {idx, fingerprint} of userInfo.fingerprints.map((fingerprint, idx) => ({idx, fingerprint}))) {
|
||||
await gpg.getKeygrip(fingerprint).then(keygrip => {
|
||||
expect(keygrip.length).toEqual(userInfo.keygrips[i].length);
|
||||
expect(keygrip).toEqual(userInfo.keygrips[i]);
|
||||
expect(keygrip.length).toEqual(userInfo.keygrips[idx].length);
|
||||
expect(keygrip).toEqual(userInfo.keygrips[idx]);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
@ -128,6 +128,16 @@ for (const userInfo of userInfos) {
|
|||
});
|
||||
});
|
||||
|
||||
describe('setTrustLevel', () => {
|
||||
it('set trust level', async () => {
|
||||
await gpg.importKey(userInfo.pgp);
|
||||
await gpg.configureAgent(gpg.agentConfig);
|
||||
expect(() => {
|
||||
gpg.setTrustLevel(userInfo.keyID, '5');
|
||||
}).not.toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
describe('deleteKey', () => {
|
||||
// eslint-disable-next-line jest/expect-expect
|
||||
it('removes key from GnuPG', async () => {
|
||||
|
|
|
@ -13,6 +13,9 @@ inputs:
|
|||
passphrase:
|
||||
description: 'Passphrase of the GPG private key'
|
||||
required: false
|
||||
trust_level:
|
||||
description: "Set key's trust level"
|
||||
required: false
|
||||
git_config_global:
|
||||
description: 'Set Git config global'
|
||||
default: 'false'
|
||||
|
|
2
dist/index.js
generated
vendored
2
dist/index.js
generated
vendored
File diff suppressed because one or more lines are too long
2
dist/index.js.map
generated
vendored
2
dist/index.js.map
generated
vendored
File diff suppressed because one or more lines are too long
|
@ -3,6 +3,7 @@ import * as core from '@actions/core';
|
|||
export interface Inputs {
|
||||
gpgPrivateKey: string;
|
||||
passphrase: string;
|
||||
trustLevel: string;
|
||||
gitConfigGlobal: boolean;
|
||||
gitUserSigningkey: boolean;
|
||||
gitCommitGpgsign: boolean;
|
||||
|
@ -18,6 +19,7 @@ export async function getInputs(): Promise<Inputs> {
|
|||
return {
|
||||
gpgPrivateKey: core.getInput('gpg_private_key', {required: true}),
|
||||
passphrase: core.getInput('passphrase'),
|
||||
trustLevel: core.getInput('trust_level'),
|
||||
gitConfigGlobal: core.getBooleanInput('git_config_global'),
|
||||
gitUserSigningkey: core.getBooleanInput('git_user_signingkey'),
|
||||
gitCommitGpgsign: core.getBooleanInput('git_commit_gpgsign'),
|
||||
|
|
14
src/gpg.ts
14
src/gpg.ts
|
@ -206,6 +206,20 @@ export const presetPassphrase = async (keygrip: string, passphrase: string): Pro
|
|||
return await gpgConnectAgent(`KEYINFO ${keygrip}`);
|
||||
};
|
||||
|
||||
export const setTrustLevel = async (keyID: string, trust: string): Promise<void> => {
|
||||
await exec
|
||||
.getExecOutput('gpg', ['--batch', '--no-tty', '--command-fd', '0', '--edit-key', keyID], {
|
||||
ignoreReturnCode: true,
|
||||
silent: true,
|
||||
input: Buffer.from(`trust\n${trust}\ny\nquit\n`)
|
||||
})
|
||||
.then(res => {
|
||||
if (res.stderr.length > 0 && res.exitCode != 0) {
|
||||
throw new Error(res.stderr);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const deleteKey = async (fingerprint: string): Promise<void> => {
|
||||
await exec
|
||||
.getExecOutput('gpg', ['--batch', '--yes', '--delete-secret-keys', fingerprint], {
|
||||
|
|
|
@ -81,6 +81,14 @@ async function run(): Promise<void> {
|
|||
});
|
||||
}
|
||||
|
||||
if (inputs.trustLevel) {
|
||||
await core.group(`Setting key's trust level`, async () => {
|
||||
await gpg.setTrustLevel(privateKey.keyID, inputs.trustLevel).then(() => {
|
||||
core.info(`Trust level set to ${inputs.trustLevel} for ${privateKey.keyID}`);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
await core.group(`Setting outputs`, async () => {
|
||||
core.info(`fingerprint=${fingerprint}`);
|
||||
core.setOutput('fingerprint', fingerprint);
|
||||
|
|
Loading…
Reference in a new issue