TestAPIKey_ExpiredKeyRejectedAtAuth: a key whose expires_at has passed must fail GetUserByAPIKey. This is the auth-side gate that makes the expires_at column actually enforce anything.
(t *testing.T)
| 314 | // passed must fail GetUserByAPIKey. This is the auth-side gate that |
| 315 | // makes the expires_at column actually enforce anything. |
| 316 | func TestAPIKey_ExpiredKeyRejectedAtAuth(t *testing.T) { |
| 317 | pool := testutil.TestDB(t) |
| 318 | store := identity.NewStore(pool) |
| 319 | ctx := context.Background() |
| 320 | |
| 321 | user, _ := store.CreateOrGetUser(ctx, "apikey-expired@example.com", "Owner", "google-apikey-expired") |
| 322 | |
| 323 | // Issue with a future expiry, then backdate via direct SQL — Create |
| 324 | // rejects past timestamps at the handler layer, but the store itself |
| 325 | // doesn't validate (it's the auth gate that does the enforcement). |
| 326 | future := time.Now().Add(1 * time.Hour) |
| 327 | key, _ := store.CreateAPIKey(ctx, user.ID, "soon-to-expire", &future) |
| 328 | if _, err := pool.Exec(ctx, `UPDATE api_keys SET expires_at = $1 WHERE id = $2`, |
| 329 | time.Now().Add(-1*time.Minute), key.ID); err != nil { |
| 330 | t.Fatalf("backdate: %v", err) |
| 331 | } |
| 332 | |
| 333 | if _, err := store.GetUserByAPIKey(ctx, key.PlaintextKey); err == nil { |
| 334 | t.Error("GetUserByAPIKey should reject expired keys; got success") |
| 335 | } |
| 336 | |
| 337 | // Sanity: a key with NULL expires_at issued by the same user still |
| 338 | // authenticates fine (i.e. the gate is per-row, not per-user). |
| 339 | stillValid, _ := store.CreateAPIKey(ctx, user.ID, "still-valid", nil) |
| 340 | if _, err := store.GetUserByAPIKey(ctx, stillValid.PlaintextKey); err != nil { |
| 341 | t.Errorf("never-expiring key should still authenticate: %v", err) |
| 342 | } |
| 343 | } |
| 344 | |
| 345 | func TestCreateAndGetInboundMessage(t *testing.T) { |
| 346 | pool := testutil.TestDB(t) |
nothing calls this directly
no test coverage detected