release: 1.9.0
test / test (push) Waiting to run

Application client IP allow-list restricts which addresses may submit as a SASL login; level-2 rate limits override the domain ceiling per application (higher or lower, capped at L1). Migration 0009, authips form, milter enforcement, export/import, and operator docs.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-08-18 23:51:41 +03:00
parent a8ded7ecc8
commit b4a9b93cf2
26 changed files with 457 additions and 252 deletions
+17 -30
View File
@@ -150,39 +150,26 @@ func TestDeleteRateLimitsForDomain(t *testing.T) {
}
}
func TestRateLimitActiveAndAllowsIP(t *testing.T) {
func TestRateLimitActive(t *testing.T) {
inactive := []RateLimit{
{},
{Scope: RateLimitScopeDomain, AllowedIPs: []string{"203.0.113.1"}}, // no ceiling
{Scope: RateLimitScopeDomain, MaxMessages: 5}, // no window
{Scope: RateLimitScopeApp, MaxMessages: 5, WindowSeconds: 60}, // app needs IPs
{Scope: RateLimitScopeApp, AllowedIPs: []string{"203.0.113.1"}, MaxMessages: 5}, // no window
{Scope: RateLimitScopeDomain, AllowedIPs: []string{"203.0.113.1"}}, // no ceiling
{Scope: RateLimitScopeDomain, MaxMessages: 5}, // no window
{Scope: RateLimitScopeApp, MaxMessages: 5}, // no window
}
for i, rl := range inactive {
if rl.Active() {
t.Fatalf("case %d: %+v should be inactive", i, rl)
}
}
domainActive := RateLimit{Scope: RateLimitScopeDomain, MaxMessages: 5, WindowSeconds: 60}
if !domainActive.Active() {
t.Fatalf("domain without IPs should be active: %+v", domainActive)
active := []RateLimit{
{Scope: RateLimitScopeDomain, MaxMessages: 5, WindowSeconds: 60},
{Scope: RateLimitScopeApp, MaxMessages: 5, WindowSeconds: 60},
}
appActive := RateLimit{
Scope: RateLimitScopeApp, AllowedIPs: []string{"203.0.113.1", "2001:db8::1"},
MaxMessages: 5, WindowSeconds: 60,
}
if !appActive.Active() {
t.Fatalf("should be active: %+v", appActive)
}
if !appActive.AllowsIP("203.0.113.1") || !appActive.AllowsIP("2001:db8::1") {
t.Fatalf("registered IPs should match")
}
// Equivalent textual form of the IPv6 address must still match.
if !appActive.AllowsIP("2001:0db8:0000:0000:0000:0000:0000:0001") {
t.Fatalf("expanded IPv6 form should match")
}
if appActive.AllowsIP("198.51.100.7") || appActive.AllowsIP("not-an-ip") || appActive.AllowsIP("") {
t.Fatalf("unregistered/invalid IPs must not match")
for i, rl := range active {
if !rl.Active() {
t.Fatalf("case %d: %+v should be active", i, rl)
}
}
}
@@ -219,14 +206,14 @@ func TestAutoRateLimitRecalc(t *testing.T) {
t.Fatalf("window = %d, want 3600", rl.WindowSeconds)
}
// Domain limit at ceiling; app auto must be strictly above or inactive at L1.
// Domain limit at ceiling; app auto is capped at L1 independently.
_ = st.SetRateLimit(RateLimit{
Scope: RateLimitScopeDomain, RefID: d.ID, Mode: RateLimitModeManual,
MaxMessages: 100, WindowSeconds: 3600,
})
if err := st.SetRateLimit(RateLimit{
Scope: RateLimitScopeApp, RefID: a.ID, Mode: RateLimitModeAuto,
AllowedIPs: []string{"203.0.113.1"}, AutoMultiplier: 2.0,
AutoMultiplier: 2.0,
}); err != nil {
t.Fatalf("SetRateLimit app: %v", err)
}
@@ -234,8 +221,8 @@ func TestAutoRateLimitRecalc(t *testing.T) {
t.Fatalf("RecalcAutoRateLimit app: %v", err)
}
appRL, ok, _ := st.GetRateLimit(RateLimitScopeApp, a.ID)
if ok && appRL.Active() {
t.Fatalf("app auto at L1 cap with domain at L1 should be inactive: %+v", appRL)
if !ok || !appRL.Active() || appRL.MaxMessages > 100 {
t.Fatalf("app auto at L1 cap should still be active: %+v", appRL)
}
_ = st.SetRateLimit(RateLimit{
@@ -246,8 +233,8 @@ func TestAutoRateLimitRecalc(t *testing.T) {
t.Fatalf("RecalcAutoRateLimit app: %v", err)
}
appRL, ok, _ = st.GetRateLimit(RateLimitScopeApp, a.ID)
if !ok || !appRL.Active() || appRL.MaxMessages <= 40 {
t.Fatalf("app auto should be above domain 40: %+v", appRL)
if !ok || !appRL.Active() {
t.Fatalf("app auto should remain active with domain at 40: %+v", appRL)
}
// Milter reads the stored ceiling via RateLimit(name/login).