1// SPDX-License-Identifier: AGPL-3.0-or-later
2
3package kvstore_test
4
5import (
6 "context"
7 "strings"
8 "testing"
9 "time"
10
11 "github.com/stretchr/testify/assert"
12 "github.com/stretchr/testify/require"
13
14 "bnema.dev/ermite/internal/domain"
15)
16
17func newTrustedKey(id string, at time.Time) domain.TrustedKey {
18 return domain.TrustedKey{
19 ID: id,
20 Format: domain.FormatSSH,
21 Title: "key " + id,
22 PublicKey: "ssh-ed25519 AAAA" + id,
23 Emails: []string{"ada@example.org", "ada@work.example"},
24 CreatedAt: at,
25 }
26}
27
28func TestTrustedKeysRoundTrip(t *testing.T) {
29 ctx := context.Background()
30 dir := t.TempDir()
31 s := openStore(t, dir)
32 ks := s.TrustedKeys()
33
34 k := newTrustedKey("SHA256:abc/def+ghi", created)
35 require.NoError(t, ks.CreateTrustedKey(ctx, k))
36 gpg := domain.TrustedKey{
37 ID: strings.Repeat("AB", 20), Format: domain.FormatGPG, Title: "gpg é",
38 PublicKey: "-----BEGIN PGP PUBLIC KEY BLOCK-----\n\nxyz\n-----END PGP PUBLIC KEY BLOCK-----\n",
39 Emails: []string{"grace@example.org"}, CreatedAt: created.Add(time.Hour),
40 }
41 require.NoError(t, ks.CreateTrustedKey(ctx, gpg))
42
43 list, err := ks.ListTrustedKeys(ctx)
44 require.NoError(t, err)
45 assert.Equal(t, []domain.TrustedKey{k, gpg}, list)
46 assert.False(t, list[0].Builtin)
47
48 // The keys survive a restart.
49 require.NoError(t, s.Close(ctx))
50 list, err = openStore(t, dir).TrustedKeys().ListTrustedKeys(ctx)
51 require.NoError(t, err)
52 assert.Equal(t, []domain.TrustedKey{k, gpg}, list)
53}
54
55func TestTrustedKeysEmptyAndInvalid(t *testing.T) {
56 ctx := context.Background()
57 ks := openStore(t, t.TempDir()).TrustedKeys()
58
59 list, err := ks.ListTrustedKeys(ctx)
60 require.NoError(t, err)
61 assert.Empty(t, list)
62
63 assert.ErrorIs(t, ks.CreateTrustedKey(ctx, domain.TrustedKey{Title: "no id"}), domain.ErrInvalid)
64 assert.ErrorIs(t, ks.CreateTrustedKey(ctx, newTrustedKey(strings.Repeat("x", 129), created)), domain.ErrInvalid)
65 bad := newTrustedKey("k", created)
66 bad.Title = "\xff"
67 assert.ErrorIs(t, ks.CreateTrustedKey(ctx, bad), domain.ErrInvalid)
68 list, err = ks.ListTrustedKeys(ctx)
69 require.NoError(t, err)
70 assert.Empty(t, list)
71}
72
73func TestTrustedKeysDuplicateAndUnknown(t *testing.T) {
74 ctx := context.Background()
75 ks := openStore(t, t.TempDir()).TrustedKeys()
76 k := newTrustedKey("SHA256:one", created)
77 require.NoError(t, ks.CreateTrustedKey(ctx, k))
78
79 dup := newTrustedKey("SHA256:one", created.Add(time.Hour))
80 dup.Title = "other"
81 assert.ErrorIs(t, ks.CreateTrustedKey(ctx, dup), domain.ErrAlreadyExists)
82 list, err := ks.ListTrustedKeys(ctx)
83 require.NoError(t, err)
84 assert.Equal(t, []domain.TrustedKey{k}, list, "the first key is kept")
85
86 assert.ErrorIs(t, ks.DeleteTrustedKey(ctx, "SHA256:nope"), domain.ErrNotFound)
87 assert.ErrorIs(t, ks.DeleteTrustedKey(ctx, ""), domain.ErrNotFound)
88}
89
90func TestTrustedKeysDelete(t *testing.T) {
91 ctx := context.Background()
92 ks := openStore(t, t.TempDir()).TrustedKeys()
93 a, b := newTrustedKey("a", created), newTrustedKey("b", created.Add(time.Hour))
94 require.NoError(t, ks.CreateTrustedKey(ctx, a))
95 require.NoError(t, ks.CreateTrustedKey(ctx, b))
96
97 require.NoError(t, ks.DeleteTrustedKey(ctx, "a"))
98 assert.ErrorIs(t, ks.DeleteTrustedKey(ctx, "a"), domain.ErrNotFound)
99 list, err := ks.ListTrustedKeys(ctx)
100 require.NoError(t, err)
101 assert.Equal(t, []domain.TrustedKey{b}, list)
102
103 // A deleted id can be trusted again.
104 require.NoError(t, ks.CreateTrustedKey(ctx, a))
105}
106
107// List orders by creation time, then by id.
108func TestTrustedKeysListOrder(t *testing.T) {
109 ctx := context.Background()
110 ks := openStore(t, t.TempDir()).TrustedKeys()
111 for _, k := range []domain.TrustedKey{
112 newTrustedKey("c", created.Add(2*time.Hour)),
113 newTrustedKey("b", created),
114 newTrustedKey("a", created),
115 newTrustedKey("d", created.Add(time.Hour)),
116 } {
117 require.NoError(t, ks.CreateTrustedKey(ctx, k))
118 }
119 list, err := ks.ListTrustedKeys(ctx)
120 require.NoError(t, err)
121 var ids []string
122 for _, k := range list {
123 ids = append(ids, k.ID)
124 }
125 assert.Equal(t, []string{"a", "b", "d", "c"}, ids)
126}