~james/core

core/spindle/mill/debug_key_test.go -rw-r--r-- 3.7 KiB
452f17b7 — james chore(import): snapshot james.dad.town/core at f70c71c7696a 14 hours ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
package mill

import (
	"context"
	"crypto/ed25519"
	"crypto/rand"
	"io"
	"log/slog"
	"testing"

	"github.com/bluesky-social/indigo/atproto/syntax"
	gossh "golang.org/x/crypto/ssh"

	millproto "tangled.org/core/spindle/mill/proto"
	millv1 "tangled.org/core/spindle/mill/proto/gen"
)

type fakeDebugChecker struct {
	allow bool
	repos []syntax.DID
}

func (f *fakeDebugChecker) DebugKeyAllowed(_ context.Context, repo syntax.DID, _ gossh.PublicKey) bool {
	f.repos = append(f.repos, repo)
	return f.allow
}

func wireKey(t *testing.T) []byte {
	t.Helper()
	pub, _, err := ed25519.GenerateKey(rand.Reader)
	if err != nil {
		t.Fatal(err)
	}
	key, err := gossh.NewPublicKey(pub)
	if err != nil {
		t.Fatal(err)
	}
	return key.Marshal()
}

type debugKeyEnv struct {
	m       *Mill
	sess    *millSession
	checker *fakeDebugChecker
	replies []*millv1.DebugKeyResponse
}

func newDebugKeyEnv(t *testing.T, allow bool) *debugKeyEnv {
	t.Helper()
	e := &debugKeyEnv{checker: &fakeDebugChecker{allow: allow}}
	e.m = New(slog.New(slog.NewTextHandler(io.Discard, nil)), Config{})
	e.m.SetDebugKeyChecker(e.checker)
	e.sess = newSession("node-a", "epoch-a", nil, scriptedEncoder(func(msg *millproto.Message) error {
		e.replies = append(e.replies, msg.GetDebugKeyResp())
		return nil
	}), slog.New(slog.NewTextHandler(io.Discard, nil)))
	lease := newLease("lease-1", "node-a", "epoch-a", "microvm")
	lease.repoDID = "did:plc:leaserepo"
	e.m.leases["lease-1"] = lease
	return e
}

func (e *debugKeyEnv) ask(t *testing.T, leaseID string, key []byte) *millv1.DebugKeyResponse {
	t.Helper()
	e.replies = nil
	e.m.handleDebugKeyRequest(e.sess, &millv1.DebugKeyRequest{RequestId: "r1", LeaseId: leaseID, PublicKey: key})
	if len(e.replies) != 1 || e.replies[0].GetRequestId() != "r1" {
		t.Fatalf("replies = %v, want exactly one for r1", e.replies)
	}
	return e.replies[0]
}

func TestMillAnswersADebugKeyFromTheLeasesRepo(t *testing.T) {
	for _, allow := range []bool{true, false} {
		e := newDebugKeyEnv(t, allow)
		resp := e.ask(t, "lease-1", wireKey(t))
		if resp.GetAllowed() != allow || resp.GetError() != "" {
			t.Errorf("checker said %v, mill answered %+v", allow, resp)
		}
		if len(e.checker.repos) != 1 || e.checker.repos[0] != "did:plc:leaserepo" {
			t.Errorf("checker asked about %v, want the lease's repo", e.checker.repos)
		}
	}
}

func TestMillRefusesADebugKeyForALeaseItDoesNotKnow(t *testing.T) {
	e := newDebugKeyEnv(t, true)
	if resp := e.ask(t, "no-such-lease", wireKey(t)); resp.GetAllowed() || resp.GetError() == "" {
		t.Errorf("unknown lease answered %+v, want a refusal with an error", resp)
	}

	// another node's lease is not this executor's to ask about
	other := newLease("lease-2", "node-b", "epoch-b", "microvm")
	other.repoDID = "did:plc:otherrepo"
	e.m.leases["lease-2"] = other
	if resp := e.ask(t, "lease-2", wireKey(t)); resp.GetAllowed() {
		t.Errorf("another node's lease answered %+v, want a refusal", resp)
	}

	// same node after a reconnect under a new epoch
	stale := newLease("lease-3", "node-a", "old-epoch", "microvm")
	stale.repoDID = "did:plc:otherrepo"
	e.m.leases["lease-3"] = stale
	if resp := e.ask(t, "lease-3", wireKey(t)); resp.GetAllowed() {
		t.Errorf("a stale epoch answered %+v, want a refusal", resp)
	}
	if len(e.checker.repos) != 0 {
		t.Errorf("checker consulted for %v, want it left alone", e.checker.repos)
	}
}

func TestMillRefusesADebugKeyItCannotCheck(t *testing.T) {
	e := newDebugKeyEnv(t, true)
	if resp := e.ask(t, "lease-1", []byte("not a key")); resp.GetAllowed() || resp.GetError() == "" {
		t.Errorf("garbage key answered %+v, want a refusal with an error", resp)
	}

	e.m.SetDebugKeyChecker(nil)
	if resp := e.ask(t, "lease-1", wireKey(t)); resp.GetAllowed() || resp.GetError() == "" {
		t.Errorf("no checker answered %+v, want a refusal with an error", resp)
	}
}