@@ -0,0 +1,90 @@ |
| 1 | +# GPG keys & commit signing |
| 2 | + |
| 3 | +Uploading an OpenPGP public key lets shithub mark your signed |
| 4 | +commits and tags as **Verified**. Verification runs server-side |
| 5 | +against the bytes git stored in each commit object — there is no |
| 6 | +client-side trust ceremony. |
| 7 | + |
| 8 | +## 1. Generate an OpenPGP key |
| 9 | + |
| 10 | +Skip this if you already have a signing key (`gpg --list-secret-keys --keyid-format=long` |
| 11 | +shows what you have). |
| 12 | + |
| 13 | +```sh |
| 14 | +gpg --full-generate-key |
| 15 | +``` |
| 16 | + |
| 17 | +Pick `ECC (sign and encrypt)` and `Curve 25519` when prompted — |
| 18 | +ed25519 is the modern default and matches what `gh` recommends. |
| 19 | +The key must carry **at least one user ID** with an email address |
| 20 | +that you have verified on your shithub account, or the resulting |
| 21 | +signatures will fall back to the `unverified_email` reason. |
| 22 | + |
| 23 | +> Encryption-only keys (e.g. a key generated for `--encrypt` |
| 24 | +> with no signing subkey) are accepted by shithub, but they can't |
| 25 | +> verify commits. The REST response surfaces `can_sign: false` |
| 26 | +> honestly when this is the case. |
| 27 | + |
| 28 | +## 2. Export the public key |
| 29 | + |
| 30 | +```sh |
| 31 | +gpg --armor --export <KEY-ID-OR-EMAIL> |
| 32 | +``` |
| 33 | + |
| 34 | +Copy the entire ASCII-armored block, including the |
| 35 | +`-----BEGIN PGP PUBLIC KEY BLOCK-----` and `END` lines. |
| 36 | + |
| 37 | +## 3. Add the key in shithub |
| 38 | + |
| 39 | +Settings → **SSH and GPG keys** → "New GPG key". Paste the block, |
| 40 | +give it a label (e.g., "laptop"), save. |
| 41 | + |
| 42 | +The page shows the primary fingerprint shithub parsed; verify it |
| 43 | +matches `gpg --fingerprint <KEY-ID>` locally before relying on |
| 44 | +the badge. |
| 45 | + |
| 46 | +## 4. Tell git to sign |
| 47 | + |
| 48 | +```sh |
| 49 | +git config --global user.signingkey <KEY-ID> |
| 50 | +git config --global commit.gpgsign true |
| 51 | +git config --global tag.gpgsign true |
| 52 | +``` |
| 53 | + |
| 54 | +Use the email on your shithub account as `user.email` — the |
| 55 | +verification cross-check compares the signature's UID emails |
| 56 | +against your account's verified emails. |
| 57 | + |
| 58 | +## 5. Push and see the badge |
| 59 | + |
| 60 | +After your next signed push, the commit list, the single-commit |
| 61 | +page, and the tag list all show a green **Verified** pill. Click |
| 62 | +it for signer + verified-at details. |
| 63 | + |
| 64 | +## What the badge states mean |
| 65 | + |
| 66 | +| Pill | Reason | Meaning | |
| 67 | +|------|--------|---------| |
| 68 | +| Green "Verified" | `valid` | Signature parsed, cryptographically checked against a registered key, signing email matches a verified email on the key. | |
| 69 | +| Yellow "Unverified" | `unknown_key` | Signature parsed but no uploaded key matches the signing subkey's fingerprint. | |
| 70 | +| Yellow "Unverified" | `unverified_email` | Signature is valid for an uploaded key, but the signing email isn't verified on that key's account. | |
| 71 | +| Yellow "Unverified" | `bad_email` | Signature is valid for an uploaded key, but the signing email isn't on the key at all. | |
| 72 | +| Yellow "Unverified" | `expired_key` | Signature is valid, but the key was expired at signing time. | |
| 73 | +| Yellow "Unverified" | `not_signing_key` | The key referenced isn't a signing key (capability bits missing). | |
| 74 | +| Yellow "Unverified" | `malformed_signature` | The signature block didn't parse. | |
| 75 | +| Yellow "Unverified" | `invalid` | Signature parsed but the cryptographic check failed. | |
| 76 | +| _no badge_ | `unsigned` | Git stored no signature header. This is the default; we don't render anything. | |
| 77 | + |
| 78 | +## Retroactive verification |
| 79 | + |
| 80 | +Uploading a key kicks off a background job that re-scans your |
| 81 | +existing commits across every repo and stamps the verification |
| 82 | +cache for the matches. Refresh the commit list a moment after |
| 83 | +upload — the badges appear without you doing anything. |
| 84 | + |
| 85 | +## Removing a key |
| 86 | + |
| 87 | +Settings → **SSH and GPG keys** → "Delete" next to the GPG key |
| 88 | +row. The verification cache rows that resolved against the |
| 89 | +deleted key are invalidated; affected commits revert to no |
| 90 | +badge until another matching key is uploaded. |