This repository has no description
1package spindle
2
3import (
4 "context"
5 "database/sql"
6 "fmt"
7 "log/slog"
8
9 "tangled.org/core/orm"
10 "tangled.org/core/spindle/db"
11 "tangled.org/core/spindle/secrets"
12)
13
14func runStartupMigrations(ctx context.Context, d *db.DB, vault secrets.Manager, logger *slog.Logger) error {
15 conn, err := d.DB.Conn(ctx)
16 if err != nil {
17 return fmt.Errorf("acquire spindle conn: %w", err)
18 }
19 defer conn.Close()
20
21 return orm.RunMigration(conn, logger, "copy-owner-rkey-secrets-to-repo-did", func(tx *sql.Tx) error {
22 return copyOwnerRkeySecretsToRepoDid(ctx, tx, vault, logger)
23 })
24}
25
26type repoSecretPair struct {
27 oldID, newID secrets.RepoIdentifier
28}
29
30func loadRepoSecretPairs(ctx context.Context, tx *sql.Tx) ([]repoSecretPair, error) {
31 rows, err := tx.QueryContext(ctx,
32 `select owner, rkey, repo_did from repos
33 where repo_did is not null and repo_did <> ''`,
34 )
35 if err != nil {
36 return nil, fmt.Errorf("select repos: %w", err)
37 }
38 defer rows.Close()
39
40 var collect func(acc []repoSecretPair) ([]repoSecretPair, error)
41 collect = func(acc []repoSecretPair) ([]repoSecretPair, error) {
42 if !rows.Next() {
43 return acc, rows.Err()
44 }
45 var owner, rkey, repoDid string
46 if err := rows.Scan(&owner, &rkey, &repoDid); err != nil {
47 return acc, fmt.Errorf("scan repos row: %w", err)
48 }
49 return collect(append(acc, repoSecretPair{
50 oldID: secrets.RepoIdentifier(owner + "/" + rkey),
51 newID: secrets.RepoIdentifier(repoDid),
52 }))
53 }
54 return collect(nil)
55}
56
57func copyOwnerRkeySecretsToRepoDid(ctx context.Context, tx *sql.Tx, vault secrets.Manager, logger *slog.Logger) error {
58 pairs, err := loadRepoSecretPairs(ctx, tx)
59 if err != nil {
60 return err
61 }
62
63 var step func(remaining []repoSecretPair, totalCopied int) error
64 step = func(remaining []repoSecretPair, totalCopied int) error {
65 if len(remaining) == 0 {
66 logger.Info("secret copy migration complete", "rows", len(pairs), "copied", totalCopied)
67 return nil
68 }
69 p := remaining[0]
70 n, err := copyRepoSecrets(ctx, vault, p.oldID, p.newID)
71 if err != nil {
72 return fmt.Errorf("copy %s -> %s: %w", p.oldID, p.newID, err)
73 }
74 if n > 0 {
75 logger.Info("secrets copied", "old", p.oldID, "new", p.newID, "count", n)
76 }
77 return step(remaining[1:], totalCopied+n)
78 }
79 return step(pairs, 0)
80}