package hold import ( "bytes" "crypto/ed25519" "os" "path/filepath" "strings" "testing" "golang.org/x/crypto/ssh" ) // TestIssueRoundTrip checks that the private key we write is parseable // with the standard openssh library and that its derived public key // byte-for-byte matches the authorized_key line we handed the agent. // If this drifts — e.g. we swap from ed25519 to something else, or // mangle the comment — the operator's `ssh -i path root@ip` breaks // silently. The test is the only early-warning we have. func TestIssueRoundTrip(t *testing.T) { kp, err := Issue(42) if err != nil { t.Fatalf("Issue: %v", err) } // Parse the private key back. signer, err := ssh.ParsePrivateKey(kp.PrivatePEM) if err != nil { t.Fatalf("ParsePrivateKey: %v", err) } // The public derived from the signer must match the authorized_key line. gotAuth := strings.TrimRight(string(ssh.MarshalAuthorizedKey(signer.PublicKey())), "\n") wantAuth := kp.AuthorizedKey // Authorized_keys comment is ours; compare just the type+b64 prefix. gotParts := strings.SplitN(gotAuth, " ", 3) wantParts := strings.SplitN(wantAuth, " ", 3) if len(gotParts) < 2 || len(wantParts) < 2 { t.Fatalf("unexpected authorized_key shape got=%q want=%q", gotAuth, wantAuth) } if gotParts[0] != wantParts[0] || gotParts[1] != wantParts[1] { t.Fatalf("public key mismatch:\n got %s\n want %s", gotAuth, wantAuth) } if !strings.Contains(wantAuth, "vetting-hold-42") { t.Fatalf("authorized_key line missing run tag: %q", wantAuth) } } // TestIssueKeysAreEd25519 pins the algorithm — anything other than // ed25519 would surprise operators who've been told their hold key is // ed25519 (and would change key-file sizes, path handling, etc.). func TestIssueKeysAreEd25519(t *testing.T) { kp, err := Issue(1) if err != nil { t.Fatalf("Issue: %v", err) } signer, err := ssh.ParsePrivateKey(kp.PrivatePEM) if err != nil { t.Fatalf("ParsePrivateKey: %v", err) } if got := signer.PublicKey().Type(); got != ssh.KeyAlgoED25519 { t.Fatalf("key algorithm: got %s, want ssh-ed25519", got) } // Paranoia: the Ed25519 public key underneath should be 32 bytes. edPub, ok := signer.PublicKey().(ssh.CryptoPublicKey) if !ok { t.Fatalf("public key does not expose CryptoPublicKey") } raw, ok := edPub.CryptoPublicKey().(ed25519.PublicKey) if !ok { t.Fatalf("public key is not ed25519.PublicKey") } if len(raw) != ed25519.PublicKeySize { t.Fatalf("ed25519 pubkey size = %d, want %d", len(raw), ed25519.PublicKeySize) } } func TestWritePrivateToSetsPerms(t *testing.T) { kp, err := Issue(7) if err != nil { t.Fatalf("Issue: %v", err) } dir := t.TempDir() path := filepath.Join(dir, "nested", "hold.key") abs, err := kp.WritePrivateTo(path) if err != nil { t.Fatalf("WritePrivateTo: %v", err) } if !filepath.IsAbs(abs) { t.Fatalf("expected absolute path, got %q", abs) } buf, err := os.ReadFile(abs) if err != nil { t.Fatalf("ReadFile: %v", err) } if !bytes.Equal(buf, kp.PrivatePEM) { t.Fatalf("on-disk bytes differ from in-memory PEM") } }