✨ feat(auth): JWT secret retention policy + automatic cleanup loop (ADR-0021)
Implements the cleanup half of ADR-0021 (which had only config infrastructure landed). Non-primary expired secrets are removed by a goroutine that runs at auth.jwt.secret_retention.cleanup_interval (default 1h). Primary secret is never removed regardless of expiration — invariant preserved. Changes: - pkg/user/jwt_manager.go : add sync.Mutex protection; add RemoveExpiredSecrets() int and StartCleanupLoop(ctx, interval) methods. Reset() now also cancels any running cleanup goroutine. - pkg/user/auth_service.go : delegate to manager via new AuthService methods StartJWTSecretCleanupLoop and RemoveExpiredJWTSecrets. - pkg/user/user.go : extend AuthService interface accordingly. - pkg/server/server.go Run() : start cleanup loop tied to rootCtx so it stops on graceful shutdown. - pkg/jwt/* : same treatment on the secondary (less-used) implementation for consistency. - adr/0021-jwt-secret-retention-policy.md : Status → Implemented + fix numbering (was incorrectly "10."). Tests: - 4 new unit tests in pkg/user/jwt_manager_test.go covering RemoveExpiredSecrets (expired removed, primary preserved, future kept) and StartCleanupLoop (fires + stops on context cancel). - go test -race ./pkg/user/... passes. - Full BDD suite (auth/config/greet/health/info/jwt) still green. - BDD scenarios at @todo / @skip remain so — they require an admin endpoint /api/v1/admin/jwt/secrets which is explicitly out of scope. Verifier verdict: APPROVE_WITH_NITS — StartCleanupLoop is 34 lines (just over the 30-line guideline); 2 time.Sleeps in TestStartCleanupLoop_FiresAndStops are justified by the goroutine-timing nature of the test.
This commit is contained in:
@@ -43,6 +43,15 @@ type AuthService interface {
|
||||
RotateJWTSecret(newSecret string)
|
||||
GetJWTSecretByIndex(index int) (string, bool)
|
||||
ResetJWTSecrets() // Reset JWT secrets to initial state for test cleanup
|
||||
// StartJWTSecretCleanupLoop starts a goroutine that periodically calls
|
||||
// RemoveExpiredJWTSecrets at the given interval, stopping when ctx is
|
||||
// cancelled. Implements the cleanup half of ADR-0021. interval <= 0
|
||||
// disables the loop.
|
||||
StartJWTSecretCleanupLoop(ctx context.Context, interval time.Duration)
|
||||
// RemoveExpiredJWTSecrets triggers an immediate cleanup pass and returns
|
||||
// the count of removed non-primary expired secrets. Useful for tests
|
||||
// driving cleanup synchronously.
|
||||
RemoveExpiredJWTSecrets() int
|
||||
}
|
||||
|
||||
// UserManager defines interface for user management operations
|
||||
|
||||
Reference in New Issue
Block a user