From 35dfd1f5e04de201465d4f28d26ceb9d75bfcf97 Mon Sep 17 00:00:00 2001 From: sneak Date: Mon, 9 Nov 2026 20:59:45 +0000 Subject: [PATCH] Core Rule Set: test concurrent requests keep their own exclusions A Drupal and a WordPress request are inspected at once, many times over, on one Core Rule Set. Coraza v3.8.1 shares each rule's exclusions between requests, so the test fails under -race. Model: opus-5-5 --- internal/coreruleset/coreruleset_test.go | 37 ++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/internal/coreruleset/coreruleset_test.go b/internal/coreruleset/coreruleset_test.go index bfdf50a..f695303 100644 --- a/internal/coreruleset/coreruleset_test.go +++ b/internal/coreruleset/coreruleset_test.go @@ -13,6 +13,7 @@ import ( "slices" "strconv" "strings" + "sync" "testing" "sneak.berlin/go/smallwebwaf/internal/coreruleset" @@ -39,6 +40,42 @@ func newCoreRuleSet(t *testing.T, level int, disabled ...int) *coreruleset.CoreR return crs } +// TestConcurrentRequestsKeepTheirOwnExclusions inspects a Drupal and a +// WordPress request at once, many times over, on one Core Rule Set, as +// sww's server does. Each passes only while its own exclusions apply. +func TestConcurrentRequestsKeepTheirOwnExclusions(t *testing.T) { + t.Parallel() + + const rounds = 50 + + crs := atDefaults(t) + targets := []string{ + "/admin/people?user=docker-compose.yml&status=All&role=All&permission=All", + "/wp-admin/edit-tags.php?taxonomy=post_tag&post_type=post&s=python3", + } + + var inspecting sync.WaitGroup + + for range rounds { + for _, target := range targets { + inspecting.Go(func() { + req := httptest.NewRequestWithContext(t.Context(), http.MethodGet, + "http://git.example"+target, nil) + req.Header.Set("User-Agent", "Mozilla/5.0 (X11; Linux x86_64; rv:131.0) "+ + "Gecko/20100101 Firefox/131.0") + req.Header.Set("Accept", "text/html") + + result, _, err := crs.Inspect(req, netip.MustParseAddr("203.0.113.9"), req.Body) + if err != nil || !reflect.DeepEqual(result, coreruleset.Result{}) { + t.Errorf("GET %s: %+v, %v", target, result, err) + } + }) + } + } + + inspecting.Wait() +} + // request is a request a test inspects: its method, its target, the path // and the query as a client sends them, and its headers, each written // "Name: value".