diff --git a/spindle/server.go b/spindle/server.go index 6ce8c946c..dd2d0bc1f 100644 --- a/spindle/server.go +++ b/spindle/server.go @@ -486,28 +486,52 @@ func (s *Spindle) Start(ctx context.Context) error { } func (s *Spindle) declareTapInterest(ctx context.Context) { - repos, err := s.db.AllRepos() - if err != nil { - s.l.Warn("tap declare: failed to load known repos", "err", err) - return + repos, reposErr := s.db.AllRepos() + if reposErr != nil { + s.l.Warn("tap declare: failed to load known repos", "err", reposErr) } - seen := make(map[syntax.DID]struct{}, len(repos)) - dids := make([]syntax.DID, 0, len(repos)) - for _, r := range repos { - if r.Owner == "" { - continue + members, membersErr := s.db.GetAllDids() + if membersErr != nil { + s.l.Warn("tap declare: failed to load known members", "err", membersErr) + } + + seen := make(map[syntax.DID]struct{}, len(repos)+len(members)+1) + dids := make([]syntax.DID, 0, len(repos)+len(members)+1) + add := func(did syntax.DID) { + if did == "" { + return + } + if _, ok := seen[did]; ok { + return } - if _, ok := seen[r.Owner]; ok { + seen[did] = struct{}{} + dids = append(dids, did) + } + + owner, err := syntax.ParseDID(s.cfg.Server.Owner) + if err != nil { + s.l.Warn("tap declare: invalid configured owner", "owner", s.cfg.Server.Owner, "err", err) + } else { + add(owner) + } + for _, member := range members { + did, err := syntax.ParseDID(member) + if err != nil { + s.l.Warn("tap declare: invalid known member", "did", member, "err", err) continue } - seen[r.Owner] = struct{}{} - dids = append(dids, r.Owner) + add(did) + } + for _, repo := range repos { + add(repo.Owner) } + sort.Slice(dids, func(i, j int) bool { return dids[i] < dids[j] }) + if err := s.tap.AddOwnerDIDs(ctx, dids); err != nil { s.l.Warn("tap declare: AddRepos rejected", "count", len(dids), "err", err) return } - s.l.Info("tap declare: known owner DIDs registered", "count", len(dids)) + s.l.Info("tap declare: owner DIDs registered", "count", len(dids)) } func Run(ctx context.Context) error { diff --git a/spindle/tapclient_test.go b/spindle/tapclient_test.go index 58e4aa641..f7501a930 100644 --- a/spindle/tapclient_test.go +++ b/spindle/tapclient_test.go @@ -4,17 +4,20 @@ import ( "context" "encoding/json" "log/slog" + "net/http" + "net/http/httptest" "path/filepath" "strings" - "tangled.org/core/jetstream" "testing" "time" "github.com/bluesky-social/indigo/atproto/identity" "github.com/bluesky-social/indigo/atproto/syntax" + "tangled.org/core/api/tangled" "tangled.org/core/eventconsumer" "tangled.org/core/idresolver" + "tangled.org/core/jetstream" "tangled.org/core/notifier" "tangled.org/core/rbac" "tangled.org/core/spindle/artifactstore" @@ -22,11 +25,53 @@ import ( "tangled.org/core/spindle/db" "tangled.org/core/spindle/models" "tangled.org/core/spindle/secrets" - "tangled.org/core/workflow" - "tangled.org/core/tapc" + "tangled.org/core/workflow" ) +func TestDeclareTapInterestBootstrapsConfiguredOwner(t *testing.T) { + d, _ := newTestSpindleDB(t) + owner := syntax.DID("did:plc:spindleowner") + requests := make(chan []syntax.DID, 1) + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodPost || r.URL.Path != "/repos/add" { + http.NotFound(w, r) + return + } + var body struct { + DIDs []syntax.DID `json:"dids"` + } + if err := json.NewDecoder(r.Body).Decode(&body); err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + requests <- body.DIDs + w.WriteHeader(http.StatusOK) + })) + defer server.Close() + + cfg := &config.Config{} + cfg.Server.Owner = owner.String() + s := &Spindle{ + db: d, + l: slog.Default(), + cfg: cfg, + } + tapClient := tapc.NewClient(server.URL, "") + s.tap = &Tap{spindle: s, tap: tapClient} + + s.declareTapInterest(context.Background()) + + select { + case dids := <-requests: + if len(dids) != 1 || dids[0] != owner { + t.Fatalf("tap interest = %v, want [%s]", dids, owner) + } + default: + t.Fatal("configured owner was not declared to tap") + } +} + func TestProcessRepo_MembershipCheck(t *testing.T) { d, e := newTestSpindleDB(t)