tenseleyflow/shithub / ee55fd7

Browse files

sqlc: GetUserGPGKeyForVerification + ListAllActiveReposWithOwner + GetRepoForBackfill

Authored by mfwolffe <wolffemf@dukes.jmu.edu>
SHA
ee55fd793e887390089ef1a293c0525c409fc64a
Parents
12b7ca3
Tree
a41ecdf

6 changed files

StatusFile+-
M internal/repos/queries/repos.sql 31 0
M internal/repos/sqlc/querier.go 10 0
M internal/repos/sqlc/repos.sql.go 84 0
M internal/users/queries/user_gpg_keys.sql 14 0
M internal/users/sqlc/querier.go 7 0
M internal/users/sqlc/user_gpg_keys.sql.go 41 0
internal/repos/queries/repos.sqlmodified
@@ -354,6 +354,37 @@ JOIN users u ON u.id = r.owner_user_id
354354
 WHERE r.deleted_at IS NULL
355355
 ORDER BY r.id;
356356
 
357
+-- name: ListAllActiveReposWithOwner :many
358
+-- Used by the GPG verification backfill (S51) to enumerate every
359
+-- active repo system-wide. Unlike ListAllRepoFullNames this query
360
+-- handles BOTH user-owned and org-owned repos via a COALESCE between
361
+-- users.username and orgs.slug; the owner string is whatever
362
+-- RepoFS.RepoPath expects.
363
+SELECT
364
+    r.id,
365
+    r.name,
366
+    r.default_branch,
367
+    COALESCE(u.username, o.slug) AS owner
368
+FROM repos r
369
+LEFT JOIN users u ON u.id = r.owner_user_id
370
+LEFT JOIN orgs  o ON o.id = r.owner_org_id
371
+WHERE r.deleted_at IS NULL
372
+ORDER BY r.id;
373
+
374
+-- name: GetRepoForBackfill :one
375
+-- Lookup the per-repo backfill metadata. Mirrors the row shape of
376
+-- ListAllActiveReposWithOwner so the per-repo job handler can run
377
+-- the same code path the bulk handler uses.
378
+SELECT
379
+    r.id,
380
+    r.name,
381
+    r.default_branch,
382
+    COALESCE(u.username, o.slug) AS owner
383
+FROM repos r
384
+LEFT JOIN users u ON u.id = r.owner_user_id
385
+LEFT JOIN orgs  o ON o.id = r.owner_org_id
386
+WHERE r.id = $1 AND r.deleted_at IS NULL;
387
+
357388
 -- ─── S27 forks ─────────────────────────────────────────────────────
358389
 
359390
 -- name: CreateForkRepo :one
internal/repos/sqlc/querier.gomodified
@@ -75,6 +75,10 @@ type Querier interface {
7575
 	// O(1) cost the user-side path enjoys.
7676
 	GetRepoByOwnerOrgAndName(ctx context.Context, db DBTX, arg GetRepoByOwnerOrgAndNameParams) (Repo, error)
7777
 	GetRepoByOwnerUserAndName(ctx context.Context, db DBTX, arg GetRepoByOwnerUserAndNameParams) (Repo, error)
78
+	// Lookup the per-repo backfill metadata. Mirrors the row shape of
79
+	// ListAllActiveReposWithOwner so the per-repo job handler can run
80
+	// the same code path the bulk handler uses.
81
+	GetRepoForBackfill(ctx context.Context, db DBTX, id int64) (GetRepoForBackfillRow, error)
7882
 	// Returns the owner slug for a repo. Used by size-recalc, indexing, and
7983
 	// other jobs that need the bare-repo on-disk path. Org-owned repos use the
8084
 	// org slug in the same path position as user-owned repos.
@@ -98,6 +102,12 @@ type Querier interface {
98102
 	// SoftDeleteSubkeysForGPGKey so the cache and the keyring stay in
99103
 	// sync. The next read of an invalidated row triggers a re-verify.
100104
 	InvalidateVerificationsForSubkey(ctx context.Context, db DBTX, signerSubkeyID pgtype.Int8) error
105
+	// Used by the GPG verification backfill (S51) to enumerate every
106
+	// active repo system-wide. Unlike ListAllRepoFullNames this query
107
+	// handles BOTH user-owned and org-owned repos via a COALESCE between
108
+	// users.username and orgs.slug; the owner string is whatever
109
+	// RepoFS.RepoPath expects.
110
+	ListAllActiveReposWithOwner(ctx context.Context, db DBTX) ([]ListAllActiveReposWithOwnerRow, error)
101111
 	// Used by `shithubd hooks reinstall --all` to enumerate every active
102112
 	// bare repo on disk and re-link its hooks.
103113
 	ListAllRepoFullNames(ctx context.Context, db DBTX) ([]ListAllRepoFullNamesRow, error)
internal/repos/sqlc/repos.sql.gomodified
@@ -466,6 +466,40 @@ func (q *Queries) GetRepoByOwnerUserAndName(ctx context.Context, db DBTX, arg Ge
466466
 	return i, err
467467
 }
468468
 
469
+const getRepoForBackfill = `-- name: GetRepoForBackfill :one
470
+SELECT
471
+    r.id,
472
+    r.name,
473
+    r.default_branch,
474
+    COALESCE(u.username, o.slug) AS owner
475
+FROM repos r
476
+LEFT JOIN users u ON u.id = r.owner_user_id
477
+LEFT JOIN orgs  o ON o.id = r.owner_org_id
478
+WHERE r.id = $1 AND r.deleted_at IS NULL
479
+`
480
+
481
+type GetRepoForBackfillRow struct {
482
+	ID            int64
483
+	Name          string
484
+	DefaultBranch string
485
+	Owner         string
486
+}
487
+
488
+// Lookup the per-repo backfill metadata. Mirrors the row shape of
489
+// ListAllActiveReposWithOwner so the per-repo job handler can run
490
+// the same code path the bulk handler uses.
491
+func (q *Queries) GetRepoForBackfill(ctx context.Context, db DBTX, id int64) (GetRepoForBackfillRow, error) {
492
+	row := db.QueryRow(ctx, getRepoForBackfill, id)
493
+	var i GetRepoForBackfillRow
494
+	err := row.Scan(
495
+		&i.ID,
496
+		&i.Name,
497
+		&i.DefaultBranch,
498
+		&i.Owner,
499
+	)
500
+	return i, err
501
+}
502
+
469503
 const getRepoOwnerUsernameByID = `-- name: GetRepoOwnerUsernameByID :one
470504
 SELECT COALESCE(u.username::varchar, o.slug::varchar) AS owner_username, r.name AS repo_name
471505
 FROM repos r
@@ -631,6 +665,56 @@ func (q *Queries) InsertRepoTopic(ctx context.Context, db DBTX, arg InsertRepoTo
631665
 	return err
632666
 }
633667
 
668
+const listAllActiveReposWithOwner = `-- name: ListAllActiveReposWithOwner :many
669
+SELECT
670
+    r.id,
671
+    r.name,
672
+    r.default_branch,
673
+    COALESCE(u.username, o.slug) AS owner
674
+FROM repos r
675
+LEFT JOIN users u ON u.id = r.owner_user_id
676
+LEFT JOIN orgs  o ON o.id = r.owner_org_id
677
+WHERE r.deleted_at IS NULL
678
+ORDER BY r.id
679
+`
680
+
681
+type ListAllActiveReposWithOwnerRow struct {
682
+	ID            int64
683
+	Name          string
684
+	DefaultBranch string
685
+	Owner         string
686
+}
687
+
688
+// Used by the GPG verification backfill (S51) to enumerate every
689
+// active repo system-wide. Unlike ListAllRepoFullNames this query
690
+// handles BOTH user-owned and org-owned repos via a COALESCE between
691
+// users.username and orgs.slug; the owner string is whatever
692
+// RepoFS.RepoPath expects.
693
+func (q *Queries) ListAllActiveReposWithOwner(ctx context.Context, db DBTX) ([]ListAllActiveReposWithOwnerRow, error) {
694
+	rows, err := db.Query(ctx, listAllActiveReposWithOwner)
695
+	if err != nil {
696
+		return nil, err
697
+	}
698
+	defer rows.Close()
699
+	items := []ListAllActiveReposWithOwnerRow{}
700
+	for rows.Next() {
701
+		var i ListAllActiveReposWithOwnerRow
702
+		if err := rows.Scan(
703
+			&i.ID,
704
+			&i.Name,
705
+			&i.DefaultBranch,
706
+			&i.Owner,
707
+		); err != nil {
708
+			return nil, err
709
+		}
710
+		items = append(items, i)
711
+	}
712
+	if err := rows.Err(); err != nil {
713
+		return nil, err
714
+	}
715
+	return items, nil
716
+}
717
+
634718
 const listAllRepoFullNames = `-- name: ListAllRepoFullNames :many
635719
 SELECT
636720
     r.id,
internal/users/queries/user_gpg_keys.sqlmodified
@@ -47,6 +47,20 @@ SELECT id, user_id, name, fingerprint, key_id, armored,
4747
 FROM user_gpg_keys
4848
 WHERE id = $1 AND user_id = $2;
4949
 
50
+-- name: GetUserGPGKeyForVerification :one
51
+-- Non-user-scoped lookup used by the verification path. Unlike
52
+-- GetUserGPGKey this query does NOT filter on user_id — the caller
53
+-- already validated the subkey resolution and needs the parent
54
+-- record's user_id to drive the email cross-check. Includes revoked
55
+-- rows so historical commit verifications can still resolve their
56
+-- signer attribution.
57
+SELECT id, user_id, name, fingerprint, key_id, armored,
58
+       can_sign, can_encrypt_comms, can_encrypt_storage, can_certify, can_authenticate,
59
+       uids, subkeys, primary_algo,
60
+       created_at, last_used_at, revoked_at, expires_at
61
+FROM user_gpg_keys
62
+WHERE id = $1;
63
+
5064
 -- name: GetUserGPGKeyByFingerprint :one
5165
 -- Uniqueness probe used by the add path to surface a friendly
5266
 -- "this key is already registered" error before the unique index
internal/users/sqlc/querier.gomodified
@@ -92,6 +92,13 @@ type Querier interface {
9292
 	// violation. Returns any row matching the fingerprint regardless of
9393
 	// which user owns it (global uniqueness is the contract).
9494
 	GetUserGPGKeyByFingerprint(ctx context.Context, db DBTX, fingerprint string) (UserGpgKey, error)
95
+	// Non-user-scoped lookup used by the verification path. Unlike
96
+	// GetUserGPGKey this query does NOT filter on user_id — the caller
97
+	// already validated the subkey resolution and needs the parent
98
+	// record's user_id to drive the email cross-check. Includes revoked
99
+	// rows so historical commit verifications can still resolve their
100
+	// signer attribution.
101
+	GetUserGPGKeyForVerification(ctx context.Context, db DBTX, id int64) (UserGpgKey, error)
95102
 	// Hot path for commit/tag signature verification. The signature
96103
 	// packet carries the signing subkey's fingerprint; this query
97104
 	// resolves it back to the primary key (and via FK to the user).
internal/users/sqlc/user_gpg_keys.sql.gomodified
@@ -105,6 +105,47 @@ func (q *Queries) GetUserGPGKeyByFingerprint(ctx context.Context, db DBTX, finge
105105
 	return i, err
106106
 }
107107
 
108
+const getUserGPGKeyForVerification = `-- name: GetUserGPGKeyForVerification :one
109
+SELECT id, user_id, name, fingerprint, key_id, armored,
110
+       can_sign, can_encrypt_comms, can_encrypt_storage, can_certify, can_authenticate,
111
+       uids, subkeys, primary_algo,
112
+       created_at, last_used_at, revoked_at, expires_at
113
+FROM user_gpg_keys
114
+WHERE id = $1
115
+`
116
+
117
+// Non-user-scoped lookup used by the verification path. Unlike
118
+// GetUserGPGKey this query does NOT filter on user_id — the caller
119
+// already validated the subkey resolution and needs the parent
120
+// record's user_id to drive the email cross-check. Includes revoked
121
+// rows so historical commit verifications can still resolve their
122
+// signer attribution.
123
+func (q *Queries) GetUserGPGKeyForVerification(ctx context.Context, db DBTX, id int64) (UserGpgKey, error) {
124
+	row := db.QueryRow(ctx, getUserGPGKeyForVerification, id)
125
+	var i UserGpgKey
126
+	err := row.Scan(
127
+		&i.ID,
128
+		&i.UserID,
129
+		&i.Name,
130
+		&i.Fingerprint,
131
+		&i.KeyID,
132
+		&i.Armored,
133
+		&i.CanSign,
134
+		&i.CanEncryptComms,
135
+		&i.CanEncryptStorage,
136
+		&i.CanCertify,
137
+		&i.CanAuthenticate,
138
+		&i.Uids,
139
+		&i.Subkeys,
140
+		&i.PrimaryAlgo,
141
+		&i.CreatedAt,
142
+		&i.LastUsedAt,
143
+		&i.RevokedAt,
144
+		&i.ExpiresAt,
145
+	)
146
+	return i, err
147
+}
148
+
108149
 const insertUserGPGKey = `-- name: InsertUserGPGKey :one
109150
 
110151
 INSERT INTO user_gpg_keys (