Format Go with gofmt, then golines -m 77 (closes #215)
check / check (push) Failing after 3m31s
check / check (push) Failing after 3m31s
script/fmt now runs golines -m 77 after gofmt, repeating golines until it changes nothing, since one pass can leave a line the next splits. script/fmt-check fails when either would change a file. script/bootstrap installs golines v0.13.0 with go install, pinned to its commit, and checks the installed version with go version -m. The tree is reformatted. The longer lines this makes are fixed by hand: nolint directives moved onto their own line above the statement, one string split, and 20 functions over funlen's 80 lines shortened or split, RunWAF and limitPercentages among them. Model: opus-5-5
This commit was merged in pull request #363.
This commit is contained in:
1 parent
63e58e326b
commit
0b23352767
118 files changed
+9447
-2670
No files matched your search
+317
-79
@@ -185,7 +185,13 @@ func (s *WAF) history() ratelimit.History {
|
||||
func (s *WAF) metrics() string {
|
||||
s.t.Helper()
|
||||
|
||||
req := newRequest(s.t, http.MethodGet, s.addr, waf.MetricsPath, http.NoBody)
|
||||
req := newRequest(
|
||||
s.t,
|
||||
http.MethodGet,
|
||||
s.addr,
|
||||
waf.MetricsPath,
|
||||
http.NoBody,
|
||||
)
|
||||
req.Header.Set("Authorization", bearer)
|
||||
|
||||
got := do(s.t, req)
|
||||
@@ -195,13 +201,22 @@ func (s *WAF) metrics() string {
|
||||
}
|
||||
|
||||
// wantDisposition checks an answer's status and disposition.
|
||||
func wantDisposition(t *testing.T, got answer, status int, disposition string) {
|
||||
func wantDisposition(
|
||||
t *testing.T,
|
||||
got answer,
|
||||
status int,
|
||||
disposition string,
|
||||
) {
|
||||
t.Helper()
|
||||
wantStatus(t, got, status)
|
||||
|
||||
if answered := got.header.Get(waf.DispositionHeader); answered !=
|
||||
disposition {
|
||||
t.Errorf("answered with disposition %q, want %q", answered, disposition)
|
||||
t.Errorf(
|
||||
"answered with disposition %q, want %q",
|
||||
answered,
|
||||
disposition,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -228,8 +243,13 @@ func wantProcessMessages(t *testing.T, s *WAF, msg string, count int) {
|
||||
}
|
||||
|
||||
if found != count {
|
||||
t.Errorf("%d process warnings %q, want %d; output:\n%s", found, msg, count,
|
||||
s.out.text())
|
||||
t.Errorf(
|
||||
"%d process warnings %q, want %d; output:\n%s",
|
||||
found,
|
||||
msg,
|
||||
count,
|
||||
s.out.text(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -259,15 +279,21 @@ func TestQuestionAllowedIsAnsweredAndLogged(t *testing.T) {
|
||||
wantBody(t, got, "")
|
||||
|
||||
if id := got.header.Get(requestIDHeader); id != "" {
|
||||
t.Errorf("answered with the id %q, want none: rproxy makes the id", id)
|
||||
t.Errorf(
|
||||
"answered with the id %q, want none: rproxy makes the id",
|
||||
id,
|
||||
)
|
||||
}
|
||||
|
||||
line := s.out.requestLine(t)
|
||||
wantLine(t, line, http.StatusOK, requestlog.ActionForward)
|
||||
|
||||
if line.ClientIP != client || line.PeerIP != rproxyPeer || line.Host != siteA ||
|
||||
line.Path != "/page" || line.Query != "q=1&token=visible" ||
|
||||
line.RequestID != "the-id" || line.Scheme != "https" ||
|
||||
if line.ClientIP != client || line.PeerIP != rproxyPeer ||
|
||||
line.Host != siteA ||
|
||||
line.Path != "/page" ||
|
||||
line.Query != "q=1&token=visible" ||
|
||||
line.RequestID != "the-id" ||
|
||||
line.Scheme != "https" ||
|
||||
line.ContentLength != 1234 ||
|
||||
line.WAFLine != requestlog.WAFLineDecision {
|
||||
t.Errorf("log line is %+v", line.Line)
|
||||
@@ -297,7 +323,11 @@ func TestIPv4VisitorInIPv6FormIsTheIPv4Client(t *testing.T) {
|
||||
|
||||
line := s.out.requestLine(t)
|
||||
if line.ClientIP != client || line.PeerIP != rproxyPeer {
|
||||
t.Errorf("log line has client_ip %q and peer_ip %q", line.ClientIP, line.PeerIP)
|
||||
t.Errorf(
|
||||
"log line has client_ip %q and peer_ip %q",
|
||||
line.ClientIP,
|
||||
line.PeerIP,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -344,7 +374,10 @@ func TestMalformedQuestionGets400AndAWarningAndNoLine(t *testing.T) {
|
||||
|
||||
metrics := s.metrics()
|
||||
if strings.Contains(metrics, `status_class="4xx"`) {
|
||||
t.Errorf("a refused question is counted in the metrics:\n%s", metrics)
|
||||
t.Errorf(
|
||||
"a refused question is counted in the metrics:\n%s",
|
||||
metrics,
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -365,7 +398,9 @@ func TestQuestionWithABodyOver64KiBGets400(t *testing.T) {
|
||||
|
||||
s := startWAF(t, "", nil)
|
||||
|
||||
over := strings.NewReader(strings.Repeat("x", waf.QuestionBodyMaxBytes+1))
|
||||
over := strings.NewReader(
|
||||
strings.Repeat("x", waf.QuestionBodyMaxBytes+1),
|
||||
)
|
||||
got := do(t, s.questionWith(http.MethodPost, siteA, client, "/", over))
|
||||
wantDisposition(t, got, http.StatusBadRequest, "")
|
||||
wantProcessMessages(t, s, "a question is refused", 1)
|
||||
@@ -390,7 +425,12 @@ func TestQuestionWithAHeldIDIsRefused(t *testing.T) {
|
||||
|
||||
// A denied request's id is held as well.
|
||||
denied := s.question(siteA, otherClient, waf.HealthPath)
|
||||
wantDisposition(t, do(t, denied), http.StatusNotFound, waf.DispositionDeny)
|
||||
wantDisposition(
|
||||
t,
|
||||
do(t, denied),
|
||||
http.StatusNotFound,
|
||||
waf.DispositionDeny,
|
||||
)
|
||||
|
||||
again = s.question(siteA, client, "/")
|
||||
again.Header.Set(requestIDHeader, denied.Header.Get(requestIDHeader))
|
||||
@@ -463,7 +503,10 @@ func TestReportNeverReachesAQuestionStillBeingHandled(t *testing.T) {
|
||||
line := s.out.requestLine(t)
|
||||
if line.ResponseBytes != 0 ||
|
||||
line.WAFLine != requestlog.WAFLineDecision {
|
||||
t.Errorf("the report reached the question being handled: %+v", line.Line)
|
||||
t.Errorf(
|
||||
"the report reached the question being handled: %+v",
|
||||
line.Line,
|
||||
)
|
||||
}
|
||||
|
||||
if held := s.server.Ledger.Snapshot(); len(held) != 0 {
|
||||
@@ -495,10 +538,18 @@ func TestPeerAbsentOrUnreadableIsAnsweredAndLoggedInvalid(t *testing.T) {
|
||||
req.Header.Set(waf.PeerHeader, peer)
|
||||
}
|
||||
|
||||
wantDisposition(t, do(t, req), http.StatusOK, waf.DispositionAllow)
|
||||
wantDisposition(
|
||||
t,
|
||||
do(t, req),
|
||||
http.StatusOK,
|
||||
waf.DispositionAllow,
|
||||
)
|
||||
|
||||
if line := s.out.requestLine(t); line.PeerIP != "invalid IP" {
|
||||
t.Errorf("log line has peer_ip %q, want invalid IP", line.PeerIP)
|
||||
t.Errorf(
|
||||
"log line has peer_ip %q, want invalid IP",
|
||||
line.PeerIP,
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -512,15 +563,26 @@ func TestContentLengthUnreadableOrNegativeCountsAsAbsent(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
s := startWAF(t, "", map[string]string{
|
||||
rulesDir: writeRules(t, "any-length header:Content-Length block .\n"),
|
||||
rulesDir: writeRules(
|
||||
t,
|
||||
"any-length header:Content-Length block .\n",
|
||||
),
|
||||
})
|
||||
|
||||
req := s.question(siteA, client, "/")
|
||||
req.Header.Set(waf.ContentLengthHeader, announced)
|
||||
wantDisposition(t, do(t, req), http.StatusOK, waf.DispositionAllow)
|
||||
wantDisposition(
|
||||
t,
|
||||
do(t, req),
|
||||
http.StatusOK,
|
||||
waf.DispositionAllow,
|
||||
)
|
||||
|
||||
if line := s.out.requestLine(t); line.ContentLength != 0 {
|
||||
t.Errorf("log line has content_length %d, want none", line.ContentLength)
|
||||
t.Errorf(
|
||||
"log line has content_length %d, want none",
|
||||
line.ContentLength,
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -596,8 +658,12 @@ func TestQuestionWhoseBodyStopsArrivingGetsNoAnswer(t *testing.T) {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
s := startWAFWith(t, "", map[string]string{metricsToken: token},
|
||||
func(server *waf.Server) { server.ReadTimeout = readTimeout })
|
||||
s := startWAFWith(
|
||||
t,
|
||||
"",
|
||||
map[string]string{metricsToken: token},
|
||||
func(server *waf.Server) { server.ReadTimeout = readTimeout },
|
||||
)
|
||||
|
||||
conn := dial(t, s.addr)
|
||||
sendQuestionWithPartOfItsBody(t, conn)
|
||||
@@ -610,17 +676,30 @@ func TestQuestionWhoseBodyStopsArrivingGetsNoAnswer(t *testing.T) {
|
||||
|
||||
sent, err := io.ReadAll(conn)
|
||||
if err != nil || len(sent) != 0 {
|
||||
t.Errorf("rproxy read %q (%v), want the connection closed unanswered",
|
||||
sent, err)
|
||||
t.Errorf(
|
||||
"rproxy read %q (%v), want the connection closed unanswered",
|
||||
sent,
|
||||
err,
|
||||
)
|
||||
}
|
||||
|
||||
wantProcessMessages(t, s, "a question's body stopped arriving", 1)
|
||||
wantProcessMessages(
|
||||
t,
|
||||
s,
|
||||
"a question's body stopped arriving",
|
||||
1,
|
||||
)
|
||||
wantNoRequestLines(t, s)
|
||||
|
||||
// The id was not taken.
|
||||
again := s.question(siteA, client, "/")
|
||||
again.Header.Set(requestIDHeader, "an-id")
|
||||
wantDisposition(t, do(t, again), http.StatusOK, waf.DispositionAllow)
|
||||
wantDisposition(
|
||||
t,
|
||||
do(t, again),
|
||||
http.StatusOK,
|
||||
waf.DispositionAllow,
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -639,7 +718,12 @@ func TestQuestionDeniedGetsTheBanResponse(t *testing.T) {
|
||||
got := s.ask(client, "/")
|
||||
wantDisposition(t, got, status, waf.DispositionDeny)
|
||||
wantBody(t, got, http.StatusText(status)+"\n")
|
||||
wantLine(t, s.out.requestLine(t), status, requestlog.ActionClientDenied)
|
||||
wantLine(
|
||||
t,
|
||||
s.out.requestLine(t),
|
||||
status,
|
||||
requestlog.ActionClientDenied,
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -656,11 +740,18 @@ func TestBanResponseCloseIsAnAnswerOfItsOwn(t *testing.T) {
|
||||
wantBody(t, got, "")
|
||||
// The visitor is sent nothing.
|
||||
wantLine(t, s.out.requestLine(t), 0, requestlog.ActionClientDenied)
|
||||
wantMetric(t, s.metrics(), `sww_requests_total{action="client_denied",instance="`+
|
||||
alertInstance+`",status_class="none"}`, 1)
|
||||
wantMetric(
|
||||
t,
|
||||
s.metrics(),
|
||||
`sww_requests_total{action="client_denied",instance="`+
|
||||
alertInstance+`",status_class="none"}`,
|
||||
1,
|
||||
)
|
||||
}
|
||||
|
||||
func TestBlockRuleIsDeniedWith403AndABanRuleWithTheBanResponse(t *testing.T) {
|
||||
func TestBlockRuleIsDeniedWith403AndABanRuleWithTheBanResponse(
|
||||
t *testing.T,
|
||||
) {
|
||||
t.Parallel()
|
||||
|
||||
s := startWAF(t, "", map[string]string{
|
||||
@@ -679,7 +770,9 @@ func TestBlockRuleIsDeniedWith403AndABanRuleWithTheBanResponse(t *testing.T) {
|
||||
requestlog.ActionTemporarilyBanned)
|
||||
}
|
||||
|
||||
func TestQuestionUnderTheOwnPrefixIsDeniedWith404AfterTheChecks(t *testing.T) {
|
||||
func TestQuestionUnderTheOwnPrefixIsDeniedWith404AfterTheChecks(
|
||||
t *testing.T,
|
||||
) {
|
||||
t.Parallel()
|
||||
|
||||
s := startWAF(t, "", map[string]string{
|
||||
@@ -693,7 +786,12 @@ func TestQuestionUnderTheOwnPrefixIsDeniedWith404AfterTheChecks(t *testing.T) {
|
||||
wantDisposition(t, got, http.StatusNotFound, waf.DispositionDeny)
|
||||
}
|
||||
|
||||
wantLine(t, s.out.requestLine(t), http.StatusNotFound, requestlog.ActionOwnEndpoint)
|
||||
wantLine(
|
||||
t,
|
||||
s.out.requestLine(t),
|
||||
http.StatusNotFound,
|
||||
requestlog.ActionOwnEndpoint,
|
||||
)
|
||||
|
||||
got := s.ask(otherClient, waf.MetricsPath)
|
||||
wantDisposition(t, got, http.StatusForbidden, waf.DispositionDeny)
|
||||
@@ -712,7 +810,9 @@ func TestObserveModeAllowsAndLogsWhatEnforceModeWouldHaveDone(t *testing.T) {
|
||||
wantWouldAction(t, line, requestlog.ActionClientDenied)
|
||||
}
|
||||
|
||||
func TestObserveModeRefusalAnsweredAllowCountsForTheErrorBurst(t *testing.T) {
|
||||
func TestObserveModeRefusalAnsweredAllowCountsForTheErrorBurst(
|
||||
t *testing.T,
|
||||
) {
|
||||
t.Parallel()
|
||||
|
||||
s := startWAF(t, "", map[string]string{
|
||||
@@ -725,9 +825,14 @@ func TestObserveModeRefusalAnsweredAllowCountsForTheErrorBurst(t *testing.T) {
|
||||
}
|
||||
|
||||
lines := s.out.requestLines(t, 2)
|
||||
if lines[0].LimitHit != "" || lines[1].LimitHit != requestlog.LimitHitMinuteRefusals {
|
||||
t.Errorf("log lines have limit_hit %q and %q, want none and %q",
|
||||
lines[0].LimitHit, lines[1].LimitHit, requestlog.LimitHitMinuteRefusals)
|
||||
if lines[0].LimitHit != "" ||
|
||||
lines[1].LimitHit != requestlog.LimitHitMinuteRefusals {
|
||||
t.Errorf(
|
||||
"log lines have limit_hit %q and %q, want none and %q",
|
||||
lines[0].LimitHit,
|
||||
lines[1].LimitHit,
|
||||
requestlog.LimitHitMinuteRefusals,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -744,9 +849,14 @@ func TestDeniedQuestionCountsForTheErrorBurst(t *testing.T) {
|
||||
}
|
||||
|
||||
lines := s.out.requestLines(t, 2)
|
||||
if lines[0].LimitHit != "" || lines[1].LimitHit != requestlog.LimitHitMinuteRefusals {
|
||||
t.Errorf("log lines have limit_hit %q and %q, want none and %q",
|
||||
lines[0].LimitHit, lines[1].LimitHit, requestlog.LimitHitMinuteRefusals)
|
||||
if lines[0].LimitHit != "" ||
|
||||
lines[1].LimitHit != requestlog.LimitHitMinuteRefusals {
|
||||
t.Errorf(
|
||||
"log lines have limit_hit %q and %q, want none and %q",
|
||||
lines[0].LimitHit,
|
||||
lines[1].LimitHit,
|
||||
requestlog.LimitHitMinuteRefusals,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -771,10 +881,19 @@ func TestAllowCarriesTheLookupHeadersWhileTheSettingIsSet(t *testing.T) {
|
||||
got := s.ask(fromDE, "/")
|
||||
wantDisposition(t, got, http.StatusOK, waf.DispositionAllow)
|
||||
|
||||
asn, country := got.header.Get("X-Client-Asn"), got.header.Get("X-Client-Country")
|
||||
asn, country := got.header.Get(
|
||||
"X-Client-Asn",
|
||||
), got.header.Get(
|
||||
"X-Client-Country",
|
||||
)
|
||||
if asn != tc.wantASN || country != tc.wantCountry {
|
||||
t.Errorf("answered with the AS number %q and the country %q, want %q and %q",
|
||||
asn, country, tc.wantASN, tc.wantCountry)
|
||||
t.Errorf(
|
||||
"answered with the AS number %q and the country %q, want %q and %q",
|
||||
asn,
|
||||
country,
|
||||
tc.wantASN,
|
||||
tc.wantCountry,
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -832,14 +951,21 @@ func TestReportCountsAtThePercentageItsQuestionWasGiven(t *testing.T) {
|
||||
})
|
||||
|
||||
s.passedOn(fromKP)
|
||||
wantDisposition(t, s.ask(fromKP, "/"), http.StatusOK, waf.DispositionAllow)
|
||||
wantDisposition(
|
||||
t,
|
||||
s.ask(fromKP, "/"),
|
||||
http.StatusOK,
|
||||
waf.DispositionAllow,
|
||||
)
|
||||
|
||||
s.passedOn(fromDE)
|
||||
wantDisposition(t, s.ask(fromDE, "/"), http.StatusForbidden,
|
||||
waf.DispositionDeny)
|
||||
}
|
||||
|
||||
func TestReportAddsTheRequestToItsClientsHistoryAndTheAnomalyCounters(t *testing.T) {
|
||||
func TestReportAddsTheRequestToItsClientsHistoryAndTheAnomalyCounters(
|
||||
t *testing.T,
|
||||
) {
|
||||
t.Parallel()
|
||||
|
||||
s := startWAF(t, "", map[string]string{anomalyClientPerMinute: "1000"})
|
||||
@@ -847,11 +973,17 @@ func TestReportAddsTheRequestToItsClientsHistoryAndTheAnomalyCounters(t *testing
|
||||
id := s.allowed(client)
|
||||
|
||||
if requests := s.history().Requests; requests != 0 {
|
||||
t.Errorf("history holds %d requests before the report, want none", requests)
|
||||
t.Errorf(
|
||||
"history holds %d requests before the report, want none",
|
||||
requests,
|
||||
)
|
||||
}
|
||||
|
||||
if counters := s.server.Anomalies.Snapshot(); len(counters) != 0 {
|
||||
t.Errorf("anomaly counters %v before the report, want none", counters)
|
||||
t.Errorf(
|
||||
"anomaly counters %v before the report, want none",
|
||||
counters,
|
||||
)
|
||||
}
|
||||
|
||||
got := s.report(waf.Report{
|
||||
@@ -882,7 +1014,12 @@ func TestDeniedRequestIsFinishedAtItsDecision(t *testing.T) {
|
||||
s.allowed(client)
|
||||
|
||||
denied := s.question(siteA, client, "/")
|
||||
wantDisposition(t, do(t, denied), http.StatusForbidden, waf.DispositionDeny)
|
||||
wantDisposition(
|
||||
t,
|
||||
do(t, denied),
|
||||
http.StatusForbidden,
|
||||
waf.DispositionDeny,
|
||||
)
|
||||
|
||||
counters := s.server.Anomalies.Snapshot()
|
||||
if len(counters) != 1 || counters[0].Minute.Current != 1 {
|
||||
@@ -900,13 +1037,19 @@ func TestDeniedRequestIsFinishedAtItsDecision(t *testing.T) {
|
||||
wantMetric(t, s.metrics(), series, 1)
|
||||
|
||||
got := s.report(waf.Report{
|
||||
RequestID: denied.Header.Get(requestIDHeader), Status: http.StatusForbidden,
|
||||
RequestID: denied.Header.Get(
|
||||
requestIDHeader,
|
||||
), Status: http.StatusForbidden,
|
||||
ResponseBytes: 1000, DurationTotalMS: 2,
|
||||
})
|
||||
wantStatus(t, got, http.StatusNoContent)
|
||||
|
||||
if after := s.history(); after != history {
|
||||
t.Errorf("the report changed the history to %+v, from %+v", after, history)
|
||||
t.Errorf(
|
||||
"the report changed the history to %+v, from %+v",
|
||||
after,
|
||||
history,
|
||||
)
|
||||
}
|
||||
|
||||
counters = s.server.Anomalies.Snapshot()
|
||||
@@ -929,8 +1072,12 @@ func TestMetricsCountAnAllowedRequestFromItsReport(t *testing.T) {
|
||||
|
||||
metrics := s.metrics()
|
||||
wantNoSeries(t, metrics, "sww_requests_total"+series)
|
||||
wantMetric(t, metrics, `sww_requests_in_flight{instance="`+alertInstance+`"}`,
|
||||
1) // the scrape itself
|
||||
wantMetric(
|
||||
t,
|
||||
metrics,
|
||||
`sww_requests_in_flight{instance="`+alertInstance+`"}`,
|
||||
1,
|
||||
) // the scrape itself
|
||||
|
||||
got := s.report(waf.Report{
|
||||
RequestID: id, Status: http.StatusBadGateway,
|
||||
@@ -955,8 +1102,12 @@ func TestMetricsCountAnAllowedRequestFromItsReport(t *testing.T) {
|
||||
DurationTotalMS: 5,
|
||||
})
|
||||
wantStatus(t, got, http.StatusNoContent)
|
||||
wantMetric(t, unscraped.metrics(),
|
||||
`sww_request_duration_seconds_sum{instance="`+alertInstance+`"}`, 0.005)
|
||||
wantMetric(
|
||||
t,
|
||||
unscraped.metrics(),
|
||||
`sww_request_duration_seconds_sum{instance="`+alertInstance+`"}`,
|
||||
0.005,
|
||||
)
|
||||
}
|
||||
|
||||
func TestReportForARequestNotHeldIsIgnored(t *testing.T) {
|
||||
@@ -988,7 +1139,11 @@ func TestReportForARequestNotHeldIsIgnored(t *testing.T) {
|
||||
}
|
||||
|
||||
if counted := s.history().ResponseBytes; counted != answerBytes {
|
||||
t.Errorf("history holds %d response bytes, want %d", counted, answerBytes)
|
||||
t.Errorf(
|
||||
"history holds %d response bytes, want %d",
|
||||
counted,
|
||||
answerBytes,
|
||||
)
|
||||
}
|
||||
|
||||
// The question's line and one for the first report, none for the second.
|
||||
@@ -1061,7 +1216,11 @@ func TestReportThatIsNotOneObjectWithAllItsFieldsIsRefused(t *testing.T) {
|
||||
wantStatus(t, s.reportBody(whole), http.StatusNoContent)
|
||||
|
||||
if counted := s.history().ResponseBytes; counted != answerBytes {
|
||||
t.Errorf("history holds %d response bytes, want %d", counted, answerBytes)
|
||||
t.Errorf(
|
||||
"history holds %d response bytes, want %d",
|
||||
counted,
|
||||
answerBytes,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1073,21 +1232,35 @@ func TestReportOver1MiBIsRefusedAndOneOfExactly1MiBIsTaken(t *testing.T) {
|
||||
id := s.allowed(client)
|
||||
// The padding is a field of no meaning here, so only the size can refuse it.
|
||||
padded := func(size int) string {
|
||||
return encodedReport(t, id, map[string]any{"padding": strings.Repeat("x", size)})
|
||||
return encodedReport(
|
||||
t,
|
||||
id,
|
||||
map[string]any{"padding": strings.Repeat("x", size)},
|
||||
)
|
||||
}
|
||||
paddingBytes := reportBodyLimit - len(padded(0))
|
||||
|
||||
wantStatus(t, s.reportBody(padded(paddingBytes+1)), http.StatusBadRequest)
|
||||
wantStatus(
|
||||
t,
|
||||
s.reportBody(padded(paddingBytes+1)),
|
||||
http.StatusBadRequest,
|
||||
)
|
||||
wantProcessMessages(t, s, "a report is refused", 1)
|
||||
|
||||
if requests := s.history().Requests; requests != 0 {
|
||||
t.Errorf("history holds %d requests, want the refused report not counted", requests)
|
||||
t.Errorf(
|
||||
"history holds %d requests, want the refused report not counted",
|
||||
requests,
|
||||
)
|
||||
}
|
||||
|
||||
wantStatus(t, s.reportBody(padded(paddingBytes)), http.StatusNoContent)
|
||||
|
||||
if requests := s.history().Requests; requests != 1 {
|
||||
t.Errorf("history holds %d requests, want the report of 1 MiB counted", requests)
|
||||
t.Errorf(
|
||||
"history holds %d requests, want the report of 1 MiB counted",
|
||||
requests,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1192,7 +1365,10 @@ func wantReportsFields(t *testing.T, line logLine) {
|
||||
line.RequestBytes != bodyBytes || line.ResponseBytes != answerBytes ||
|
||||
line.DurationTotalMS != 12.5 || line.DurationUpstreamTotalMS == nil ||
|
||||
*line.DurationUpstreamTotalMS != 10.25 {
|
||||
t.Errorf("the report's line lacks the report's fields: %+v", line.Line)
|
||||
t.Errorf(
|
||||
"the report's line lacks the report's fields: %+v",
|
||||
line.Line,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1220,7 +1396,11 @@ func wantSameDecision(t *testing.T, reported, decided logLine) {
|
||||
|
||||
// wantDecisionsFields checks what waf answered and noted on the decision's
|
||||
// line, of a request with these fields.
|
||||
func wantDecisionsFields(t *testing.T, line logLine, id, query, accept string) {
|
||||
func wantDecisionsFields(
|
||||
t *testing.T,
|
||||
line logLine,
|
||||
id, query, accept string,
|
||||
) {
|
||||
t.Helper()
|
||||
|
||||
if line.WAFLine != requestlog.WAFLineDecision ||
|
||||
@@ -1234,7 +1414,9 @@ func wantDecisionsFields(t *testing.T, line logLine, id, query, accept string) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestReportWritesTheLastLineWithTheDecisionsAndTheReportsFields(t *testing.T) {
|
||||
func TestReportWritesTheLastLineWithTheDecisionsAndTheReportsFields(
|
||||
t *testing.T,
|
||||
) {
|
||||
t.Parallel()
|
||||
|
||||
s := startWAF(t, "", map[string]string{
|
||||
@@ -1353,29 +1535,46 @@ func TestOldestAnsweredRequestIsDroppedPastTheBound(t *testing.T) {
|
||||
t.Fatalf("question: %v", err)
|
||||
}
|
||||
|
||||
wantDisposition(t, readAnswer(res), http.StatusOK, waf.DispositionAllow)
|
||||
wantDisposition(
|
||||
t,
|
||||
readAnswer(res),
|
||||
http.StatusOK,
|
||||
waf.DispositionAllow,
|
||||
)
|
||||
}
|
||||
|
||||
// The table is full again with next and those, without oldest.
|
||||
got := s.report(waf.Report{RequestID: oldest, ResponseBytes: answerBytes})
|
||||
got := s.report(
|
||||
waf.Report{RequestID: oldest, ResponseBytes: answerBytes},
|
||||
)
|
||||
wantStatus(t, got, http.StatusNoContent)
|
||||
|
||||
if counted := s.history().Requests; counted != 0 {
|
||||
t.Errorf("history holds %d requests, want the dropped one not counted", counted)
|
||||
t.Errorf(
|
||||
"history holds %d requests, want the dropped one not counted",
|
||||
counted,
|
||||
)
|
||||
}
|
||||
|
||||
got = s.report(waf.Report{RequestID: next, ResponseBytes: answerBytes})
|
||||
wantStatus(t, got, http.StatusNoContent)
|
||||
|
||||
if counted := s.history().Requests; counted != 1 {
|
||||
t.Errorf("history holds %d requests, want the one still held", counted)
|
||||
t.Errorf(
|
||||
"history holds %d requests, want the one still held",
|
||||
counted,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBanMadeThroughOneHostRefusesTheClientOnAnother(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
s := startWAF(t, "", map[string]string{rulesDir: writeRules(t, testRules)})
|
||||
s := startWAF(
|
||||
t,
|
||||
"",
|
||||
map[string]string{rulesDir: writeRules(t, testRules)},
|
||||
)
|
||||
|
||||
got := do(t, s.question(siteA, client, "/.env"))
|
||||
wantDisposition(t, got, http.StatusForbidden, waf.DispositionDeny)
|
||||
@@ -1385,17 +1584,29 @@ func TestBanMadeThroughOneHostRefusesTheClientOnAnother(t *testing.T) {
|
||||
|
||||
lines := s.out.requestLines(t, 2)
|
||||
if lines[0].Host != siteA || lines[1].Host != siteB {
|
||||
t.Errorf("log lines have the hosts %q and %q", lines[0].Host, lines[1].Host)
|
||||
t.Errorf(
|
||||
"log lines have the hosts %q and %q",
|
||||
lines[0].Host,
|
||||
lines[1].Host,
|
||||
)
|
||||
}
|
||||
|
||||
held := s.server.Ledger.Snapshot()
|
||||
if len(held) != 1 || held[0].Notes.Request.Host != siteA {
|
||||
t.Errorf("bans held are %+v, want one whose notes name %s", held, siteA)
|
||||
t.Errorf(
|
||||
"bans held are %+v, want one whose notes name %s",
|
||||
held,
|
||||
siteA,
|
||||
)
|
||||
}
|
||||
|
||||
waiting := s.queue.Snapshot().Waiting[alerts.DestinationWebhook]
|
||||
if len(waiting) == 0 || waiting[0].Host != siteA {
|
||||
t.Errorf("alerts waiting are %+v, want the ban's, naming %s", waiting, siteA)
|
||||
t.Errorf(
|
||||
"alerts waiting are %+v, want the ban's, naming %s",
|
||||
waiting,
|
||||
siteA,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1441,7 +1652,12 @@ func TestOwnEndpointsAnswerOnlyWithoutTheClientHeader(t *testing.T) {
|
||||
req.Header.Set("Authorization", tc.authorization)
|
||||
|
||||
if strings.HasPrefix(tc.path, "/_sww/") {
|
||||
wantDisposition(t, do(t, req), http.StatusNotFound, waf.DispositionDeny)
|
||||
wantDisposition(
|
||||
t,
|
||||
do(t, req),
|
||||
http.StatusNotFound,
|
||||
waf.DispositionDeny,
|
||||
)
|
||||
} else {
|
||||
wantDisposition(t, do(t, req), http.StatusOK, waf.DispositionAllow)
|
||||
}
|
||||
@@ -1494,7 +1710,12 @@ func TestLogLevelHoldsBackNoRequestLine(t *testing.T) {
|
||||
wantStatus(t, do(t, req), http.StatusBadRequest)
|
||||
|
||||
s.allowed(client)
|
||||
wantLine(t, s.out.requestLine(t), http.StatusOK, requestlog.ActionForward)
|
||||
wantLine(
|
||||
t,
|
||||
s.out.requestLine(t),
|
||||
http.StatusOK,
|
||||
requestlog.ActionForward,
|
||||
)
|
||||
|
||||
for _, line := range s.out.lines(t) {
|
||||
if line["type"] == "process" {
|
||||
@@ -1508,10 +1729,15 @@ func TestServerHasTheTimeLimitsSPECGives(t *testing.T) {
|
||||
|
||||
s := startWAF(t, "", nil)
|
||||
|
||||
if s.server.ReadTimeout != time.Minute || s.server.WriteTimeout != time.Minute ||
|
||||
if s.server.ReadTimeout != time.Minute ||
|
||||
s.server.WriteTimeout != time.Minute ||
|
||||
s.server.IdleTimeout != 2*time.Minute {
|
||||
t.Errorf("the read, write and idle limits are %v, %v and %v, want 1m, 1m and 2m",
|
||||
s.server.ReadTimeout, s.server.WriteTimeout, s.server.IdleTimeout)
|
||||
t.Errorf(
|
||||
"the read, write and idle limits are %v, %v and %v, want 1m, 1m and 2m",
|
||||
s.server.ReadTimeout,
|
||||
s.server.WriteTimeout,
|
||||
s.server.IdleTimeout,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1584,10 +1810,14 @@ func TestCoreRuleSetAlertNamesTheSite(t *testing.T) {
|
||||
wantDisposition(t, got, http.StatusForbidden, waf.DispositionDeny)
|
||||
|
||||
waiting := s.queue.Snapshot().Waiting[alerts.DestinationWebhook]
|
||||
if len(waiting) != 1 || waiting[0].Event != alerts.EventCoreRuleSetMatch ||
|
||||
if len(waiting) != 1 ||
|
||||
waiting[0].Event != alerts.EventCoreRuleSetMatch ||
|
||||
waiting[0].Host != siteA {
|
||||
t.Errorf("alerts waiting are %+v, want a core_rule_set_match naming %s",
|
||||
waiting, siteA)
|
||||
t.Errorf(
|
||||
"alerts waiting are %+v, want a core_rule_set_match naming %s",
|
||||
waiting,
|
||||
siteA,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1603,7 +1833,11 @@ func TestReputationHitAlertNamesTheSite(t *testing.T) {
|
||||
waiting := s.queue.Snapshot().Waiting[alerts.DestinationWebhook]
|
||||
if len(waiting) != 1 || waiting[0].Event != alerts.EventReputationHit ||
|
||||
waiting[0].Host != siteA {
|
||||
t.Errorf("alerts waiting are %+v, want a reputation_hit naming %s", waiting, siteA)
|
||||
t.Errorf(
|
||||
"alerts waiting are %+v, want a reputation_hit naming %s",
|
||||
waiting,
|
||||
siteA,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1619,6 +1853,10 @@ func TestAnomalyAlertNamesTheSite(t *testing.T) {
|
||||
waiting := s.queue.Snapshot().Waiting[alerts.DestinationWebhook]
|
||||
if len(waiting) != 1 || waiting[0].Event != alerts.EventAnomaly ||
|
||||
waiting[0].Host != siteA {
|
||||
t.Errorf("alerts waiting are %+v, want an anomaly naming %s", waiting, siteA)
|
||||
t.Errorf(
|
||||
"alerts waiting are %+v, want an anomaly naming %s",
|
||||
waiting,
|
||||
siteA,
|
||||
)
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user