mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
feat: purge expired api keys in dbpurge (#20863)
closes https://github.com/coder/coder/issues/19889 This is in response to a migration in v2.27 that takes very long on deployments with large `api_key` tables.
This commit is contained in:
@@ -7835,3 +7835,81 @@ func TestUpdateAIBridgeInterceptionEnded(t *testing.T) {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestDeleteExpiredAPIKeys(t *testing.T) {
|
||||
t.Parallel()
|
||||
db, _ := dbtestutil.NewDB(t)
|
||||
|
||||
// Constant time for testing
|
||||
now := time.Date(2025, 11, 20, 12, 0, 0, 0, time.UTC)
|
||||
expiredBefore := now.Add(-time.Hour) // Anything before this is expired
|
||||
|
||||
ctx := testutil.Context(t, testutil.WaitLong)
|
||||
|
||||
user := dbgen.User(t, db, database.User{})
|
||||
|
||||
expiredTimes := []time.Time{
|
||||
expiredBefore.Add(-time.Hour * 24 * 365),
|
||||
expiredBefore.Add(-time.Hour * 24),
|
||||
expiredBefore.Add(-time.Hour),
|
||||
expiredBefore.Add(-time.Minute),
|
||||
expiredBefore.Add(-time.Second),
|
||||
}
|
||||
for _, exp := range expiredTimes {
|
||||
// Expired api keys
|
||||
dbgen.APIKey(t, db, database.APIKey{UserID: user.ID, ExpiresAt: exp})
|
||||
}
|
||||
|
||||
unexpiredTimes := []time.Time{
|
||||
expiredBefore.Add(time.Hour * 24 * 365),
|
||||
expiredBefore.Add(time.Hour * 24),
|
||||
expiredBefore.Add(time.Hour),
|
||||
expiredBefore.Add(time.Minute),
|
||||
expiredBefore.Add(time.Second),
|
||||
}
|
||||
for _, unexp := range unexpiredTimes {
|
||||
// Unexpired api keys
|
||||
dbgen.APIKey(t, db, database.APIKey{UserID: user.ID, ExpiresAt: unexp})
|
||||
}
|
||||
|
||||
// All keys are present before deletion
|
||||
keys, err := db.GetAPIKeysByUserID(ctx, database.GetAPIKeysByUserIDParams{
|
||||
LoginType: user.LoginType,
|
||||
UserID: user.ID,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.Len(t, keys, len(expiredTimes)+len(unexpiredTimes))
|
||||
|
||||
// Delete expired keys
|
||||
// First verify the limit works by deleting one at a time
|
||||
deletedCount, err := db.DeleteExpiredAPIKeys(ctx, database.DeleteExpiredAPIKeysParams{
|
||||
Before: expiredBefore,
|
||||
LimitCount: 1,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, int64(1), deletedCount)
|
||||
|
||||
// Ensure it was deleted
|
||||
remaining, err := db.GetAPIKeysByUserID(ctx, database.GetAPIKeysByUserIDParams{
|
||||
LoginType: user.LoginType,
|
||||
UserID: user.ID,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.Len(t, remaining, len(expiredTimes)+len(unexpiredTimes)-1)
|
||||
|
||||
// Delete the rest of the expired keys
|
||||
deletedCount, err = db.DeleteExpiredAPIKeys(ctx, database.DeleteExpiredAPIKeysParams{
|
||||
Before: expiredBefore,
|
||||
LimitCount: 100,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, int64(len(expiredTimes)-1), deletedCount)
|
||||
|
||||
// Ensure only unexpired keys remain
|
||||
remaining, err = db.GetAPIKeysByUserID(ctx, database.GetAPIKeysByUserIDParams{
|
||||
LoginType: user.LoginType,
|
||||
UserID: user.ID,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.Len(t, remaining, len(unexpiredTimes))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user