tinyrelayfile
tinyrelay/tinygit/maintainers_test.go/

tinygit/maintainers_test.go raw
1package tinygit
2
3import (
4 "context"
5 "path/filepath"
6 "strings"
7 "testing"
8
9 "github.com/FelineStateMachine/tinyrelay/internal/event"
10 "github.com/FelineStateMachine/tinyrelay/internal/storage"
11)
12
13type maintainerFunc func(context.Context, Repository, string) bool
14
15func (f maintainerFunc) IsMaintainer(ctx context.Context, r Repository, pubkey string) bool {
16 return f(ctx, r, pubkey)
17}
18
19// The host's maintainer answer is consulted after the owner and the
20// maintainers tag, and it decides whether a state event from another key is
21// accepted.
22func TestMaintainerSourceDecidesStateAuthority(t *testing.T) {
23 root := t.TempDir()
24 store, err := storage.Open(context.Background(), filepath.Join(root, "relay.db"))
25 if err != nil {
26 t.Fatal(err)
27 }
28 defer store.Close()
29 vouched := map[string]bool{}
30 var asked []string
31 g, err := New(Config{Store: tinyStore(store), Root: filepath.Join(root, "git"), Maintainers: maintainerFunc(func(_ context.Context, r Repository, pubkey string) bool {
32 asked = append(asked, r.Identifier+":"+pubkey)
33 return vouched[pubkey]
34 })})
35 if err != nil {
36 t.Fatal(err)
37 }
38 ownerSecret, agentSecret := strings.Repeat("0", 63)+"1", strings.Repeat("0", 63)+"2"
39 owner, _ := event.PublicKey(ownerSecret)
40 agent, _ := event.PublicKey(agentSecret)
41 announcement := event.Event{Kind: 30617, CreatedAt: 100, Tags: [][]string{{"d", "demo"}, {"clone", "https://relay.example/" + owner + "/demo.git"}}}
42 if err := event.Sign(&announcement, ownerSecret); err != nil {
43 t.Fatal(err)
44 }
45 if err := g.Publish(context.Background(), announcement); err != nil {
46 t.Fatal(err)
47 }
48 state := func(createdAt int64) event.Event {
49 e := event.Event{Kind: 30618, CreatedAt: createdAt, Tags: [][]string{{"d", "demo"}, {"HEAD", "ref: refs/heads/main"}, {"refs/heads/main", strings.Repeat("a", 40)}}}
50 if err := event.Sign(&e, agentSecret); err != nil {
51 t.Fatal(err)
52 }
53 return e
54 }
55 if _, err := g.Validate(context.Background(), state(101)); err == nil || !strings.Contains(err.Error(), "not an accepted repository maintainer") {
56 t.Fatalf("state from an unvouched key: %v", err)
57 }
58 if len(asked) == 0 || asked[0] != "demo:"+agent {
59 t.Fatalf("source was not consulted for the repository: %v", asked)
60 }
61 vouched[agent] = true
62 repo, err := g.Validate(context.Background(), state(102))
63 if err != nil {
64 t.Fatalf("state from a vouched key: %v", err)
65 }
66 if repo.Owner != owner || repo.Refs["refs/heads/main"] != strings.Repeat("a", 40) {
67 t.Fatalf("state bound to the wrong repository: %+v", repo)
68 }
69 if !g.IsMaintainer(context.Background(), repo, owner) || g.IsMaintainer(context.Background(), repo, "") {
70 t.Fatal("owner must count and an empty key must not")
71 }
72 vouched[agent] = false
73 if _, err := g.Validate(context.Background(), state(103)); err == nil {
74 t.Fatal("a withdrawn answer must reject the next state")
75 }
76}

About

ownerc01503e8035f
visibilitypublic
headd730679639bf

Maintainers

  • c01503e8035f owner
  • ba1b5beed5b5 agent hermes

Clone

  • https://012.run/npub1cq2s86qrtadf36eqq3epm38wmhdynrrcwxf84eldk3f94dkv7ttsrulrz5/tinyrelay.git

Refs