fix(security): amortize LoginThrottle.Prune off the failed-bind hot path (plan R2-07 T11)
This commit is contained in:
@@ -25,6 +25,12 @@ public class LoginThrottleTests
|
||||
private static LoginThrottle Create(TimeProvider clock, SecurityOptions? options = null) =>
|
||||
new(clock, Options.Create(options ?? new SecurityOptions()));
|
||||
|
||||
private static (LoginThrottle throttle, TestTimeProvider clock) Create()
|
||||
{
|
||||
var clock = new TestTimeProvider(Start);
|
||||
return (Create(clock), clock);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FiveFailuresInWindow_LocksOut_ThenWindowExpiryUnlocks()
|
||||
{
|
||||
@@ -110,4 +116,29 @@ public class LoginThrottleTests
|
||||
|
||||
Assert.False(throttle.IsLockedOut("alice", "10.0.0.1"));
|
||||
}
|
||||
|
||||
// ── arch-review R2 N8: amortized prune ─────────────────────────────────────
|
||||
|
||||
[Fact]
|
||||
public void KeySpray_MapStaysBounded_AtTheHardCap()
|
||||
{
|
||||
var (throttle, _) = Create(); // existing helper: throttle over a fake clock
|
||||
// Spray far past the cap: the over-cap eviction must run on EVERY write once
|
||||
// the cap is exceeded, regardless of the amortized cadence (arch-review R2 N8).
|
||||
for (var i = 0; i < LoginThrottle.MaxTrackedKeys + 500; i++)
|
||||
throttle.RecordFailure($"user{i}", "10.0.0.1");
|
||||
Assert.True(throttle.TrackedKeyCount <= LoginThrottle.MaxTrackedKeys);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ExpiredEntries_AreEventuallySwept_OnTheAmortizedCadence()
|
||||
{
|
||||
var (throttle, clock) = Create();
|
||||
throttle.RecordFailure("stale", "10.0.0.1");
|
||||
clock.Advance(TimeSpan.FromMinutes(10)); // window fully expired
|
||||
for (var i = 0; i < LoginThrottle.PruneEveryNFailures; i++)
|
||||
throttle.RecordFailure($"fresh{i}", "10.0.0.1"); // cadence tick fires within these
|
||||
Assert.False(throttle.IsLockedOut("stale", "10.0.0.1"));
|
||||
Assert.True(throttle.TrackedKeyCount <= LoginThrottle.PruneEveryNFailures); // "stale" swept
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user