TestLegacyKeyResolvesAccount: a pre-Slice-5a row with NULL scope resolves to account (the backfill guarantee — no key silently loses authority).
(t *testing.T)
| 117 | // TestLegacyKeyResolvesAccount: a pre-Slice-5a row with NULL scope resolves to |
| 118 | // account (the backfill guarantee — no key silently loses authority). |
| 119 | func TestLegacyKeyResolvesAccount(t *testing.T) { |
| 120 | pool := testutil.TestDB(t) |
| 121 | store := identity.NewStore(pool) |
| 122 | ctx := context.Background() |
| 123 | user, err := store.CreateOrGetUser(ctx, "legacy@example.com", "Owner", "google-legacy") |
| 124 | if err != nil { |
| 125 | t.Fatalf("CreateOrGetUser: %v", err) |
| 126 | } |
| 127 | // Simulate a legacy key inserted the pre-Slice-5a way: the INSERT does not |
| 128 | // mention the scope column at all, so migration 034's NOT NULL DEFAULT |
| 129 | // 'account' backfills it — the guarantee that no existing key loses |
| 130 | // authority on deploy. Hash the plaintext exactly as the store does. |
| 131 | plaintext := "e2a_legacykey_deadbeef" |
| 132 | if _, err := pool.Exec(ctx, |
| 133 | `INSERT INTO api_keys (id, user_id, name, key_prefix, key_hash, created_at) |
| 134 | VALUES ($1, $2, $3, $4, encode(sha256($5::bytea), 'hex'), now())`, |
| 135 | "apk_legacy", user.ID, "legacy", "e2a_legacy", plaintext, |
| 136 | ); err != nil { |
| 137 | t.Fatalf("insert legacy key: %v", err) |
| 138 | } |
| 139 | |
| 140 | p, err := store.GetPrincipalByAPIKey(ctx, plaintext) |
| 141 | if err != nil { |
| 142 | t.Fatalf("GetPrincipalByAPIKey(legacy): %v", err) |
| 143 | } |
| 144 | if p.Scope != identity.ScopeAccount { |
| 145 | t.Errorf("legacy key scope = %q, want account (backfill)", p.Scope) |
| 146 | } |
| 147 | if p.User.ID != user.ID { |
| 148 | t.Errorf("legacy key user = %s, want %s", p.User.ID, user.ID) |
| 149 | } |
| 150 | } |
nothing calls this directly
no test coverage detected