tinyrelayfile
tinyrelay/internal/daemon/repository_maintainers.go/

internal/daemon/repository_maintainers.go raw
1package daemon
2
3import (
4 "context"
5 "time"
6
7 gitrelay "github.com/FelineStateMachine/tinyrelay/tinygit"
8)
9
10// Repository maintainers. The owner and the keys in an announcement's
11// maintainers tag are maintainers by the event itself; an agent becomes one
12// through a kind 30392 grant that holds maintain on that exact repository.
13// This file is the one place that answers "does this key maintain this
14// repository", for state events and pushes through gitrelay, for status
15// changes and access checks in the daemon, and for the browse output that
16// the repository panel lists.
17
18// IsMaintainer implements gitrelay.MaintainerSource. A paused, revoked or
19// expired grant never counts. Outcomes are recorded under the authorize
20// operation; the key itself is never logged or labelled.
21func (t *Tenant) IsMaintainer(ctx context.Context, r gitrelay.Repository, pubkey string) bool {
22 if pubkey == "" {
23 return false
24 }
25 if pubkey == r.Owner || contains(r.Maintainers, pubkey) {
26 return true
27 }
28 ctx, finish := t.app.telemetry.Start(ctx, "authorize")
29 outcome := "unauthorized"
30 defer func() { finish(outcome) }()
31 grant, ok, err := t.community.AgentGrant(ctx, pubkey)
32 if err != nil {
33 outcome = "error"
34 t.app.telemetry.Logger().WarnContext(ctx, "agent maintainer lookup failed", "error", err)
35 return false
36 }
37 if ok && grant.Maintains(r.Owner, r.Identifier, time.Now().Unix()) {
38 outcome = "ok"
39 return true
40 }
41 return false
42}
43
44// repositoryMaintainers lists the owner, the announcement's maintainers and
45// every agent whose active grant holds maintain on the repository, in that
46// order. A key in the maintainers tag that also holds such a grant is
47// reported as an agent so the interface can say so.
48func (t *Tenant) repositoryMaintainers(ctx context.Context, r gitrelay.Repository) []gitrelay.Maintainer {
49 out := []gitrelay.Maintainer{{PubKey: r.Owner, Role: "owner"}}
50 seen := map[string]int{r.Owner: 0}
51 for _, pubkey := range r.Maintainers {
52 if _, dup := seen[pubkey]; dup {
53 continue
54 }
55 seen[pubkey] = len(out)
56 out = append(out, gitrelay.Maintainer{PubKey: pubkey, Role: "maintainer"})
57 }
58 grants, err := t.community.RepositoryAgents(ctx, r.Owner, r.Identifier, time.Now().Unix())
59 if err != nil {
60 t.app.telemetry.Logger().WarnContext(ctx, "repository agents lookup failed", "error", err)
61 return out
62 }
63 for _, grant := range grants {
64 if index, dup := seen[grant.Agent]; dup {
65 if index > 0 {
66 out[index].Role, out[index].Name = "agent", grant.Name
67 }
68 continue
69 }
70 seen[grant.Agent] = len(out)
71 out = append(out, gitrelay.Maintainer{PubKey: grant.Agent, Role: "agent", Name: grant.Name})
72 }
73 return out
74}
75
76// maintainerKeys returns the keys whose status events count for a
77// repository, for use as an authors filter.
78func (t *Tenant) maintainerKeys(ctx context.Context, r gitrelay.Repository) []string {
79 maintainers := t.repositoryMaintainers(ctx, r)
80 keys := make([]string, 0, len(maintainers))
81 for _, maintainer := range maintainers {
82 keys = append(keys, maintainer.PubKey)
83 }
84 return keys
85}

About

ownerc01503e8035f
visibilitypublic
headd730679639bf

Maintainers

  • c01503e8035f owner
  • ba1b5beed5b5 agent hermes

Clone

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

Refs