Monorepo for Tangled
tangled.org
1package spindle
2
3import (
4 "context"
5 "fmt"
6 "log/slog"
7
8 "github.com/bluesky-social/indigo/atproto/syntax"
9 "tangled.org/core/rbac"
10 "tangled.org/core/spindle/db"
11)
12
13func migrateLegacyRepoCasbin(ctx context.Context, d *db.DB, e *rbac.Enforcer, logger *slog.Logger, owner syntax.DID, name string, rkey syntax.RecordKey, repoDid syntax.DID) {
14 candidates := legacyKeyCandidates(owner, name, rkey)
15 if siblings, err := d.SiblingRkeysForRepoDid(owner, repoDid, rkey); err == nil {
16 var fold func(rest []string, acc []string) []string
17 fold = func(rest []string, acc []string) []string {
18 if len(rest) == 0 {
19 return acc
20 }
21 return fold(rest[1:], append(acc, owner.String()+"/"+rest[0]))
22 }
23 candidates = fold(siblings, candidates)
24 } else {
25 logger.Warn("legacy casbin rekey: sibling lookup failed", "err", err)
26 }
27 if len(candidates) == 0 {
28 return
29 }
30 flag := "legacy-casbin-rekey:" + repoDid.String() + ":" + rkey.String()
31 var exists bool
32 if err := d.QueryRowContext(ctx, `select exists (select 1 from migrations where name = ?)`, flag).Scan(&exists); err != nil {
33 logger.Warn("legacy casbin rekey: check migration flag", "err", err)
34 return
35 }
36 if exists {
37 return
38 }
39
40 if err := e.AddRepo(owner.String(), rbac.ThisServer, repoDid.String()); err != nil {
41 logger.Warn("legacy casbin rekey: owner add new key failed", "err", err)
42 return
43 }
44
45 collabs, err := d.ListCollaboratorsByRepoDid(repoDid)
46 if err != nil {
47 logger.Warn("legacy casbin rekey: list collaborators failed", "err", err)
48 return
49 }
50
51 var addCollabs func(remaining []db.RepoCollaborator) error
52 addCollabs = func(remaining []db.RepoCollaborator) error {
53 if len(remaining) == 0 {
54 return nil
55 }
56 c := remaining[0]
57 if err := e.AddCollaborator(c.Subject.String(), rbac.ThisServer, repoDid.String()); err != nil {
58 return fmt.Errorf("AddCollaborator %s -> %s: %w", c.Subject, repoDid, err)
59 }
60 return addCollabs(remaining[1:])
61 }
62 if err := addCollabs(collabs); err != nil {
63 logger.Warn("legacy casbin rekey: collaborator add failed", "err", err)
64 return
65 }
66
67 var wipeCandidates func(remaining []string) error
68 wipeCandidates = func(remaining []string) error {
69 if len(remaining) == 0 {
70 return nil
71 }
72 if err := e.WipeRepoPolicies(rbac.ThisServer, remaining[0]); err != nil {
73 return fmt.Errorf("WipeRepoPolicies %s: %w", remaining[0], err)
74 }
75 return wipeCandidates(remaining[1:])
76 }
77 if err := wipeCandidates(candidates); err != nil {
78 logger.Warn("legacy casbin rekey: wipe failed", "err", err)
79 return
80 }
81
82 if _, err := d.ExecContext(ctx, `insert or ignore into migrations (name) values (?)`, flag); err != nil {
83 logger.Warn("legacy casbin rekey: mark flag failed", "err", err)
84 return
85 }
86 logger.Info("legacy casbin rekeyed", "owner", owner, "name", name, "rkey", rkey, "repoDid", repoDid, "candidates", candidates, "collabs", len(collabs))
87}