diff --git a/backend/internal/service/api_key.go b/backend/internal/service/api_key.go index eb9f2b15..ec20b0a9 100644 --- a/backend/internal/service/api_key.go +++ b/backend/internal/service/api_key.go @@ -22,8 +22,9 @@ const ( ) // IsWindowExpired returns true if the window starting at windowStart has exceeded the given duration. +// A nil windowStart is treated as expired — no initialized window means any accumulated usage is stale. func IsWindowExpired(windowStart *time.Time, duration time.Duration) bool { - return windowStart != nil && time.Since(*windowStart) >= duration + return windowStart == nil || time.Since(*windowStart) >= duration } type APIKey struct { diff --git a/backend/internal/service/api_key_rate_limit_test.go b/backend/internal/service/api_key_rate_limit_test.go index 7fadf270..4058ca4b 100644 --- a/backend/internal/service/api_key_rate_limit_test.go +++ b/backend/internal/service/api_key_rate_limit_test.go @@ -15,10 +15,10 @@ func TestIsWindowExpired(t *testing.T) { want bool }{ { - name: "nil window start", + name: "nil window start (treated as expired)", start: nil, duration: RateLimitWindow5h, - want: false, + want: true, }, { name: "active window (started 1h ago, 5h window)", @@ -113,7 +113,7 @@ func TestAPIKey_EffectiveUsage(t *testing.T) { want7d: 0, }, { - name: "nil window starts return raw usage", + name: "nil window starts return 0 (stale usage reset)", key: APIKey{ Usage5h: 5.0, Usage1d: 10.0, @@ -122,9 +122,9 @@ func TestAPIKey_EffectiveUsage(t *testing.T) { Window1dStart: nil, Window7dStart: nil, }, - want5h: 5.0, - want1d: 10.0, - want7d: 50.0, + want5h: 0, + want1d: 0, + want7d: 0, }, { name: "mixed: 5h expired, 1d active, 7d nil", @@ -138,7 +138,7 @@ func TestAPIKey_EffectiveUsage(t *testing.T) { }, want5h: 0, want1d: 10.0, - want7d: 50.0, + want7d: 0, }, { name: "zero usage with active windows", @@ -210,7 +210,7 @@ func TestAPIKeyRateLimitData_EffectiveUsage(t *testing.T) { want7d: 0, }, { - name: "nil window starts return raw usage", + name: "nil window starts return 0 (stale usage reset)", data: APIKeyRateLimitData{ Usage5h: 3.0, Usage1d: 8.0, @@ -219,9 +219,9 @@ func TestAPIKeyRateLimitData_EffectiveUsage(t *testing.T) { Window1dStart: nil, Window7dStart: nil, }, - want5h: 3.0, - want1d: 8.0, - want7d: 40.0, + want5h: 0, + want1d: 0, + want7d: 0, }, }