package spindle
import (
"context"
"fmt"
"log/slog"
"github.com/bluesky-social/indigo/atproto/syntax"
"tangled.org/core/rbac"
"tangled.org/core/spindle/db"
)
func migrateLegacyRepoCasbin(ctx context.Context, d *db.DB, e *rbac.Enforcer, logger *slog.Logger, owner syntax.DID, name string, rkey syntax.RecordKey, repoDid syntax.DID) {
candidates := legacyKeyCandidates(owner, name, rkey)
if siblings, err := d.SiblingRkeysForRepoDid(owner, repoDid, rkey); err == nil {
var fold func(rest []string, acc []string) []string
fold = func(rest []string, acc []string) []string {
if len(rest) == 0 {
return acc
}
return fold(rest[1:], append(acc, owner.String()+"/"+rest[0]))
}
candidates = fold(siblings, candidates)
} else {
logger.Warn("legacy casbin rekey: sibling lookup failed", "err", err)
}
if len(candidates) == 0 {
return
}
flag := "legacy-casbin-rekey:" + repoDid.String() + ":" + rkey.String()
var exists bool
if err := d.QueryRowContext(ctx, `select exists (select 1 from migrations where name = ?)`, flag).Scan(&exists); err != nil {
logger.Warn("legacy casbin rekey: check migration flag", "err", err)
return
}
if exists {
return
}
if err := e.AddRepo(owner.String(), rbac.ThisServer, repoDid.String()); err != nil {
logger.Warn("legacy casbin rekey: owner add new key failed", "err", err)
return
}
collabs, err := d.ListCollaboratorsByRepoDid(repoDid)
if err != nil {
logger.Warn("legacy casbin rekey: list collaborators failed", "err", err)
return
}
var addCollabs func(remaining []db.RepoCollaborator) error
addCollabs = func(remaining []db.RepoCollaborator) error {
if len(remaining) == 0 {
return nil
}
c := remaining[0]
if err := e.AddCollaborator(c.Subject.String(), rbac.ThisServer, repoDid.String()); err != nil {
return fmt.Errorf("AddCollaborator %s -> %s: %w", c.Subject, repoDid, err)
}
return addCollabs(remaining[1:])
}
if err := addCollabs(collabs); err != nil {
logger.Warn("legacy casbin rekey: collaborator add failed", "err", err)
return
}
var wipeCandidates func(remaining []string) error
wipeCandidates = func(remaining []string) error {
if len(remaining) == 0 {
return nil
}
if err := e.WipeRepoPolicies(rbac.ThisServer, remaining[0]); err != nil {
return fmt.Errorf("WipeRepoPolicies %s: %w", remaining[0], err)
}
return wipeCandidates(remaining[1:])
}
if err := wipeCandidates(candidates); err != nil {
logger.Warn("legacy casbin rekey: wipe failed", "err", err)
return
}
if _, err := d.ExecContext(ctx, `insert or ignore into migrations (name) values (?)`, flag); err != nil {
logger.Warn("legacy casbin rekey: mark flag failed", "err", err)
return
}
logger.Info("legacy casbin rekeyed", "owner", owner, "name", name, "rkey", rkey, "repoDid", repoDid, "candidates", candidates, "collabs", len(collabs))
}