tenseleyflow/shithub / 994f5e1

Browse files

auth/gpgkey: regression test against real gpg fixtures

Authored by mfwolffe <wolffemf@dukes.jmu.edu>
SHA
994f5e194dcb9bbae4404f2e87f6caa99c058371
Parents
04e0987
Tree
26efe5f

2 changed files

StatusFile+-
M internal/auth/gpgkey/parse_test.go 42 0
M internal/auth/gpgkey/testdata/README.md 20 12
internal/auth/gpgkey/parse_test.gomodified
@@ -5,6 +5,7 @@ package gpgkey
55
 import (
66
 	"bytes"
77
 	"errors"
8
+	"os"
89
 	"strings"
910
 	"testing"
1011
 	"time"
@@ -318,6 +319,47 @@ func TestParse_NameControlChars(t *testing.T) {
318319
 	}
319320
 }
320321
 
322
+// ─── regression baseline: real gpg-produced fixtures ──────────────
323
+//
324
+// Exercises codec compatibility with output from `gpg (GnuPG)` 2.5+.
325
+// See testdata/README.md for the generation recipe.
326
+
327
+func TestParse_RealGPGFixtures(t *testing.T) {
328
+	cases := []struct {
329
+		name string
330
+		path string
331
+		algo string
332
+	}{
333
+		{"ed25519", "testdata/ed25519.asc", "ed25519"},
334
+		{"rsa4096", "testdata/rsa4096.asc", "rsa4096"},
335
+	}
336
+	for _, tc := range cases {
337
+		tc := tc
338
+		t.Run(tc.name, func(t *testing.T) {
339
+			blob, err := os.ReadFile(tc.path)
340
+			if err != nil {
341
+				t.Fatalf("ReadFile %s: %v", tc.path, err)
342
+			}
343
+			got, err := Parse("", string(blob))
344
+			if err != nil {
345
+				t.Fatalf("Parse %s: %v", tc.path, err)
346
+			}
347
+			if got.PrimaryAlgo != tc.algo {
348
+				t.Errorf("PrimaryAlgo: got %q, want %q", got.PrimaryAlgo, tc.algo)
349
+			}
350
+			if !got.CanSign && !got.CanCertify {
351
+				t.Errorf("expected sign or certify on real gpg primary; got both false")
352
+			}
353
+			if len(got.UIDs) == 0 {
354
+				t.Error("expected at least one UID")
355
+			}
356
+			if len(got.Fingerprint) != 40 || !isHex(got.Fingerprint) {
357
+				t.Errorf("Fingerprint malformed: %q", got.Fingerprint)
358
+			}
359
+		})
360
+	}
361
+}
362
+
321363
 // ─── helpers ────────────────────────────────────────────────────────
322364
 
323365
 func isHex(s string) bool {
internal/auth/gpgkey/testdata/README.mdmodified
@@ -1,19 +1,27 @@
11
 # gpgkey testdata
22
 
3
-This directory exists for future committed fixtures (real-world
4
-`gpg`-produced ASCII-armored blocks that might be useful as
5
-regression-test inputs). It is **empty by default**.
3
+Two committed fixtures — real `gpg`-produced ASCII-armored blocks
4
+serving as a regression baseline. The bulk of `parse_test.go` still
5
+synthesizes fixtures in-memory via `github.com/ProtonMail/go-crypto/openpgp`
6
+(no `gpg` dependency in CI, deterministic, no time-bomb expiry races),
7
+but these two files exercise the **codec compatibility** with real-world
8
+output from `gpg (GnuPG)`:
69
 
7
-The current `parse_test.go` synthesizes its fixtures in-memory via
8
-`github.com/ProtonMail/go-crypto/openpgp` so:
10
+- `ed25519.asc` — `gpg --quick-gen-key 'shithub-test-ed25519 <ed25519@shithub.test>' default default 0` then `--armor --export`. ed25519 primary + curve25519 encryption subkey, no expiry.
11
+- `rsa4096.asc` — `gpg --quick-gen-key 'shithub-test-rsa <rsa@shithub.test>' rsa4096 default 0` then `--armor --export`. RSA-4096 primary + RSA-4096 encryption subkey.
912
 
10
-- Tests run without `gpg` installed (CI portability).
11
-- Fixtures are deterministic (no time-bomb expiry races).
12
-- The `private` and `signature` armor-block fixtures don't have to
13
-  be committed as files (they're constructed on demand from synthesized
14
-  entities).
13
+Both are throwaway keys; no real-user material is ever committed here.
1514
 
1615
 If a future bug surfaces from a specific real-world key shape, drop the
1716
 producing key here as `<shape>.asc` and reference it from
18
-`parse_test.go` via `os.ReadFile`. Keep keys throwaway; never commit
19
-material from a real user.
17
+`parse_test.go` via `os.ReadFile`. Generation recipe (uses an isolated
18
+GNUPGHOME so it doesn't pollute the host keyring):
19
+
20
+```bash
21
+TMPHOME=$(mktemp -d) && chmod 700 "$TMPHOME"
22
+export GNUPGHOME=$TMPHOME
23
+gpg --batch --pinentry-mode loopback --passphrase '' \
24
+    --quick-gen-key '<your-test-id> <email@shithub.test>' <algo> <usage> 0
25
+gpg --armor --export <email@shithub.test> > <shape>.asc
26
+rm -rf "$TMPHOME"
27
+```