Rename the settings whose names do not say what they control (closes #234)
check / check (push) Waiting to run
check / check (push) Waiting to run
Applies the setting renames of the naming audit under the SWW_WAF_ and SWW_RPROXY_ prefixes, with sneak's names for the IP reputation cache time and the two time limits, which now take milliseconds. The rproxy log field default_disposition becomes waf_backend_no_answer, and config.Config and config.FromEnvironment become config.WAF and config.WAFFromEnvironment. Go fields, test names and prose follow. No aliases; nothing reads the old names. Model: opus-5-5
This commit was merged in pull request #370.
This commit is contained in:
1 parent
94d60358ee
commit
4dad4fff43
100 files changed
+2261
-2019
No files matched your search
@@ -15,7 +15,7 @@ import (
|
||||
"sneak.berlin/go/smallwebwaf/internal/waf"
|
||||
)
|
||||
|
||||
const errorBurstThreshold = "SWW_WAF_ERROR_BURST_THRESHOLD"
|
||||
const refusalsLimitPerMinute = "SWW_WAF_REFUSALS_LIMIT_PER_MINUTE"
|
||||
|
||||
// refused is a request the tests here send, which waf refuses after a rule
|
||||
// file match.
|
||||
@@ -48,29 +48,29 @@ func (r refused) send(s *sender, from string) logLine {
|
||||
return logLine{}
|
||||
}
|
||||
|
||||
// startForErrorBurst is startWithClock with testRules, the metrics token and
|
||||
// SWW_WAF_ERROR_BURST_THRESHOLD at threshold, and the settings in env.
|
||||
func startForErrorBurst(
|
||||
t *testing.T, threshold string, env map[string]string,
|
||||
// startForRefusalLimit is startWithClock with testRules, the metrics token and
|
||||
// SWW_WAF_REFUSALS_LIMIT_PER_MINUTE at limit, and the settings in env.
|
||||
func startForRefusalLimit(
|
||||
t *testing.T, limit string, env map[string]string,
|
||||
) (*sender, *clock, *waf.Server) {
|
||||
t.Helper()
|
||||
|
||||
settings := map[string]string{
|
||||
errorBurstThreshold: threshold,
|
||||
rulesDir: writeRules(t, testRules),
|
||||
metricsToken: token,
|
||||
refusalsLimitPerMinute: limit,
|
||||
ruleFilesDir: writeRules(t, testRules),
|
||||
metricsToken: token,
|
||||
}
|
||||
maps.Copy(settings, env)
|
||||
|
||||
return startWithClock(t, "", settings)
|
||||
}
|
||||
|
||||
func TestErrorBurstBreaksAtOneOverTheThreshold(t *testing.T) {
|
||||
func TestRefusalLimitBreaksAtOneOverTheLimit(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
for _, tc := range []struct {
|
||||
name string
|
||||
// refusals are four, one over the threshold of three.
|
||||
// refusals are four, one over the limit of three.
|
||||
refusals []refused
|
||||
// nextAction is the action of the client's next request: the next
|
||||
// request after a ban for a ban rule makes it permanent.
|
||||
@@ -90,7 +90,7 @@ func TestErrorBurstBreaksAtOneOverTheThreshold(t *testing.T) {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
s, _, _ := startForErrorBurst(t, "3", nil)
|
||||
s, _, _ := startForRefusalLimit(t, "3", nil)
|
||||
|
||||
// Three refusals break nothing, and the app's answers between
|
||||
// them are not counted.
|
||||
@@ -109,8 +109,8 @@ func TestErrorBurstBreaksAtOneOverTheThreshold(t *testing.T) {
|
||||
s.get(client, http.StatusOK, requestlog.ActionForward)
|
||||
}
|
||||
|
||||
// The fourth is answered as the others were, breaks the error
|
||||
// burst, and bans the client.
|
||||
// The fourth is answered as the others were, breaks the refusal
|
||||
// limit, and bans the client.
|
||||
line := tc.refusals[3].send(s, client)
|
||||
if line.LimitHit != requestlog.LimitHitMinuteRefusals ||
|
||||
line.Offence != requestlog.OffenceLimit {
|
||||
@@ -130,7 +130,7 @@ func TestErrorBurstBreaksAtOneOverTheThreshold(t *testing.T) {
|
||||
func TestRefusalLimitBanNamesItsHeuristicWindowCountAndLimit(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
s, _, _ := startForErrorBurst(t, "1", nil)
|
||||
s, _, _ := startForRefusalLimit(t, "1", nil)
|
||||
|
||||
const ruleFigures = `{"rule_id": "blocked", "rule_action": "block"}`
|
||||
|
||||
@@ -146,10 +146,10 @@ func TestRefusalLimitBanNamesItsHeuristicWindowCountAndLimit(t *testing.T) {
|
||||
`{"window": "minute", "count": 2, "limit": 1}`)
|
||||
}
|
||||
|
||||
func TestErrorBurstBanNotesHistoryAndMetrics(t *testing.T) {
|
||||
func TestRefusalLimitBanNotesHistoryAndMetrics(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
s, clk, server := startForErrorBurst(t, "2", nil)
|
||||
s, clk, server := startForRefusalLimit(t, "2", nil)
|
||||
start := clk.Now()
|
||||
|
||||
blockRule.send(s, client)
|
||||
@@ -221,18 +221,18 @@ func TestErrorBurstBanNotesHistoryAndMetrics(t *testing.T) {
|
||||
)
|
||||
}
|
||||
|
||||
func TestErrorBurstIsNotLoweredForAClientWithLowerLimits(t *testing.T) {
|
||||
func TestRefusalLimitIsNotLoweredForAClientWithLowerLimits(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
geojsURL, _ := startGeoJS(t)
|
||||
s, _, server := startWithClock(t, geojsURL, map[string]string{
|
||||
lookupTimeout: "1h",
|
||||
errorBurstThreshold: "2",
|
||||
rulesDir: writeRules(t, testRules),
|
||||
tagLimitPercent: countryTagDEHalf,
|
||||
asnAndCountryLookupTimeout: "3600000",
|
||||
refusalsLimitPerMinute: "2",
|
||||
ruleFilesDir: writeRules(t, testRules),
|
||||
tagLimitPercent: countryTagDEHalf,
|
||||
})
|
||||
|
||||
// Half of the threshold would be one, which the second refusal is over.
|
||||
// Half of the limit would be one, which the second refusal is over.
|
||||
for range 2 {
|
||||
line := blockRule.send(s, fromDE)
|
||||
if line.LimitHit != "" {
|
||||
@@ -252,7 +252,7 @@ func TestErrorBurstIsNotLoweredForAClientWithLowerLimits(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestErrorBurstDoesNotCountTheAppsAnswers(t *testing.T) {
|
||||
func TestRefusalLimitDoesNotCountTheAppsAnswers(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
statuses := map[string]int{
|
||||
@@ -266,8 +266,8 @@ func TestErrorBurstDoesNotCountTheAppsAnswers(t *testing.T) {
|
||||
w.WriteHeader(statuses[r.URL.Path])
|
||||
},
|
||||
map[string]string{
|
||||
errorBurstThreshold: "1",
|
||||
rulesDir: writeRules(t, testRules),
|
||||
refusalsLimitPerMinute: "1",
|
||||
ruleFilesDir: writeRules(t, testRules),
|
||||
},
|
||||
)
|
||||
|
||||
@@ -277,7 +277,7 @@ func TestErrorBurstDoesNotCountTheAppsAnswers(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// The first refusal is one, not over the threshold.
|
||||
// The first refusal is one, not over the limit.
|
||||
line := blockRule.send(s, client)
|
||||
if line.LimitHit != "" {
|
||||
t.Errorf("log line has limit_hit %q, want none", line.LimitHit)
|
||||
@@ -293,23 +293,23 @@ func TestErrorBurstDoesNotCountTheAppsAnswers(t *testing.T) {
|
||||
wantAlerts(t, queue)
|
||||
}
|
||||
|
||||
func TestErrorBurstOffOrAtItsDefault(t *testing.T) {
|
||||
func TestRefusalLimitOffOrAtItsDefault(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
for _, tc := range []struct {
|
||||
threshold string
|
||||
// broken is whether the 31st refusal breaks the error burst.
|
||||
limit string
|
||||
// broken is whether the 31st refusal breaks the refusal limit.
|
||||
broken bool
|
||||
}{
|
||||
{"", true},
|
||||
{off, false},
|
||||
} {
|
||||
t.Run(errorBurstThreshold+"="+tc.threshold, func(t *testing.T) {
|
||||
t.Run(refusalsLimitPerMinute+"="+tc.limit, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
env := map[string]string{rulesDir: writeRules(t, testRules)}
|
||||
if tc.threshold != "" {
|
||||
env[errorBurstThreshold] = tc.threshold
|
||||
env := map[string]string{ruleFilesDir: writeRules(t, testRules)}
|
||||
if tc.limit != "" {
|
||||
env[refusalsLimitPerMinute] = tc.limit
|
||||
}
|
||||
|
||||
s, _, _ := startWithClock(t, "", env)
|
||||
@@ -322,7 +322,7 @@ func TestErrorBurstOffOrAtItsDefault(t *testing.T) {
|
||||
broken := line.LimitHit == requestlog.LimitHitMinuteRefusals
|
||||
if broken != tc.broken {
|
||||
t.Errorf(
|
||||
"the 31st refusal broke the error burst: %t, want %t",
|
||||
"the 31st refusal broke the refusal limit: %t, want %t",
|
||||
broken,
|
||||
tc.broken,
|
||||
)
|
||||
@@ -331,7 +331,7 @@ func TestErrorBurstOffOrAtItsDefault(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestErrorBurstCountsEachClientTheChecksApplyTo(t *testing.T) {
|
||||
func TestRefusalLimitCountsEachClientTheChecksApplyTo(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
const (
|
||||
@@ -339,7 +339,7 @@ func TestErrorBurstCountsEachClientTheChecksApplyTo(t *testing.T) {
|
||||
exempt = "192.0.2.50" // in SWW_WAF_RATE_LIMIT_EXEMPT_NETS
|
||||
)
|
||||
|
||||
s, _, _ := startForErrorBurst(t, "1", map[string]string{
|
||||
s, _, _ := startForRefusalLimit(t, "1", map[string]string{
|
||||
allowNets: allowed, rateLimitExemptNets: exempt,
|
||||
})
|
||||
|
||||
@@ -367,10 +367,10 @@ func TestErrorBurstCountsEachClientTheChecksApplyTo(t *testing.T) {
|
||||
s.get(exempt, http.StatusForbidden, requestlog.ActionTemporarilyBanned)
|
||||
}
|
||||
|
||||
func TestErrorBurstBanSetsTheRefusalsBackToZero(t *testing.T) {
|
||||
func TestRefusalLimitBanSetsTheRefusalsBackToZero(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
s, clk, _ := startForErrorBurst(
|
||||
s, clk, _ := startForRefusalLimit(
|
||||
t,
|
||||
"1",
|
||||
map[string]string{limitBanDuration: "1s"},
|
||||
@@ -389,13 +389,13 @@ func TestErrorBurstBanSetsTheRefusalsBackToZero(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestObserveModeLogsAndAlertsTheErrorBurst(t *testing.T) {
|
||||
func TestObserveModeLogsAndAlertsABrokenRefusalLimit(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
s, clk, server, queue := startWithAlerts(t, map[string]string{
|
||||
mode: observe,
|
||||
errorBurstThreshold: "1",
|
||||
rulesDir: writeRules(t, testRules),
|
||||
mode: observe,
|
||||
refusalsLimitPerMinute: "1",
|
||||
ruleFilesDir: writeRules(t, testRules),
|
||||
})
|
||||
start := clk.Now()
|
||||
held := bans.Ban{
|
||||
|
||||
Reference in new issue
Block a user