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 is contained in:
1 parent
63e58e326b
commit
7f8a59de04
118 files changed
+9447
-2670
No files matched your search
@@ -31,7 +31,9 @@ var errHealthEndpoint = errors.New("the health endpoint answered")
|
||||
// args are the arguments after `healthcheck`; it takes none, and given
|
||||
// one it names it on stderr and returns 1 without checking anything.
|
||||
func HealthCheck(
|
||||
ctx context.Context, args []string, lookupEnv func(string) (string, bool),
|
||||
ctx context.Context,
|
||||
args []string,
|
||||
lookupEnv func(string) (string, bool),
|
||||
stderr io.Writer,
|
||||
) int {
|
||||
if len(args) > 0 {
|
||||
@@ -85,7 +87,9 @@ func checkWAF(
|
||||
func checkRProxyAndApp(
|
||||
ctx context.Context, lookupEnv func(string) (string, bool),
|
||||
) error {
|
||||
listenAddr, upstreamURL, err := config.RProxyListenAddrAndUpstreamURL(lookupEnv)
|
||||
listenAddr, upstreamURL, err := config.RProxyListenAddrAndUpstreamURL(
|
||||
lookupEnv,
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid setting: %w", err)
|
||||
}
|
||||
@@ -95,7 +99,11 @@ func checkRProxyAndApp(
|
||||
return fmt.Errorf("ask rproxy: %w", err)
|
||||
}
|
||||
|
||||
conn, err := (&net.Dialer{}).DialContext(ctx, "tcp", appAddress(upstreamURL))
|
||||
conn, err := (&net.Dialer{}).DialContext(
|
||||
ctx,
|
||||
"tcp",
|
||||
appAddress(upstreamURL),
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("connect to the app: %w", err)
|
||||
}
|
||||
@@ -109,9 +117,17 @@ func checkRProxyAndApp(
|
||||
// listenAddr, which the settings have checked has one.
|
||||
func askHealthEndpoint(ctx context.Context, listenAddr string) error {
|
||||
_, port, _ := net.SplitHostPort(listenAddr)
|
||||
health := "http://" + net.JoinHostPort("127.0.0.1", port) + waf.HealthPath
|
||||
health := "http://" + net.JoinHostPort(
|
||||
"127.0.0.1",
|
||||
port,
|
||||
) + waf.HealthPath
|
||||
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, health, http.NoBody)
|
||||
req, err := http.NewRequestWithContext(
|
||||
ctx,
|
||||
http.MethodGet,
|
||||
health,
|
||||
http.NoBody,
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("make the request: %w", err)
|
||||
}
|
||||
|
||||
@@ -94,7 +94,10 @@ func TestHealthCheckInRProxysContainer(t *testing.T) {
|
||||
site, _ := startRProxy(t, "http://127.0.0.1:9", app.URL)
|
||||
_, port, _ := net.SplitHostPort(strings.TrimPrefix(site, "http://"))
|
||||
settings := func(more ...string) map[string]string {
|
||||
env := map[string]string{rproxyListenAddr: ":" + port, rproxyUpstreamURL: app.URL}
|
||||
env := map[string]string{
|
||||
rproxyListenAddr: ":" + port,
|
||||
rproxyUpstreamURL: app.URL,
|
||||
}
|
||||
for i := 0; i < len(more); i += 2 {
|
||||
env[more[i]] = more[i+1]
|
||||
}
|
||||
@@ -107,8 +110,12 @@ func TestHealthCheckInRProxysContainer(t *testing.T) {
|
||||
wantHealthCheck(t, settings(commandSetting, "rproxy"), 0, "")
|
||||
|
||||
// SWW_COMMAND cannot be given as a file.
|
||||
wantHealthCheck(t, settings(commandSetting+"_FILE", writeFile(t, "waf\n")),
|
||||
0, "")
|
||||
wantHealthCheck(
|
||||
t,
|
||||
settings(commandSetting+"_FILE", writeFile(t, "waf\n")),
|
||||
0,
|
||||
"",
|
||||
)
|
||||
|
||||
// Another setting does not fail it, even an invalid one, and neither does
|
||||
// SWRP_WAF_BACKEND being unset.
|
||||
@@ -121,7 +128,12 @@ func TestHealthCheckInRProxysContainer(t *testing.T) {
|
||||
|
||||
// Listening on port 0 takes any free port, so nothing listens on port 0
|
||||
// itself.
|
||||
wantHealthCheck(t, settings(rproxyListenAddr, ":0"), 1, "unhealthy: ask rproxy: ")
|
||||
wantHealthCheck(
|
||||
t,
|
||||
settings(rproxyListenAddr, ":0"),
|
||||
1,
|
||||
"unhealthy: ask rproxy: ",
|
||||
)
|
||||
wantHealthCheck(t, settings(rproxyListenAddr, "8080"), 1,
|
||||
"unhealthy: invalid setting: SWRP_LISTEN_ADDR: ")
|
||||
|
||||
@@ -161,16 +173,26 @@ func TestHealthCheckRefusesAnArgument(t *testing.T) {
|
||||
// wantHealthCheck runs the health check with the settings in env, and
|
||||
// checks its exit status and the start of what it writes to stderr,
|
||||
// which is nothing when message is empty.
|
||||
func wantHealthCheck(t *testing.T, env map[string]string, status int, message string) {
|
||||
func wantHealthCheck(
|
||||
t *testing.T,
|
||||
env map[string]string,
|
||||
status int,
|
||||
message string,
|
||||
) {
|
||||
t.Helper()
|
||||
|
||||
var stderr bytes.Buffer
|
||||
|
||||
got := sww.HealthCheck(t.Context(), nil, func(name string) (string, bool) {
|
||||
value, ok := env[name]
|
||||
got := sww.HealthCheck(
|
||||
t.Context(),
|
||||
nil,
|
||||
func(name string) (string, bool) {
|
||||
value, ok := env[name]
|
||||
|
||||
return value, ok
|
||||
}, &stderr)
|
||||
return value, ok
|
||||
},
|
||||
&stderr,
|
||||
)
|
||||
|
||||
wrote := stderr.String()
|
||||
if got != status || !strings.HasPrefix(wrote, message) ||
|
||||
|
||||
+10
-2
@@ -21,7 +21,11 @@ import (
|
||||
// more severe: rproxy has no setting for either.
|
||||
func RunRProxy(ctx context.Context, params Params) int {
|
||||
hostname, _ := os.Hostname() // "" when the host has no name to give
|
||||
processLog := requestlog.NewProcessLogger(params.Stdout, hostname, slog.LevelInfo)
|
||||
processLog := requestlog.NewProcessLogger(
|
||||
params.Stdout,
|
||||
hostname,
|
||||
slog.LevelInfo,
|
||||
)
|
||||
|
||||
cfg, err := config.RProxyFromEnvironment(params.LookupEnv)
|
||||
if err != nil {
|
||||
@@ -38,7 +42,11 @@ func RunRProxy(ctx context.Context, params Params) int {
|
||||
|
||||
listener, err := (&net.ListenConfig{}).Listen(ctx, "tcp", cfg.ListenAddr)
|
||||
if err != nil {
|
||||
processLog.Error("cannot listen on SWRP_LISTEN_ADDR", "error", err.Error())
|
||||
processLog.Error(
|
||||
"cannot listen on SWRP_LISTEN_ADDR",
|
||||
"error",
|
||||
err.Error(),
|
||||
)
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
+91
-22
@@ -79,7 +79,11 @@ func startRProxy(t *testing.T, backend, appURL string) (string, *output) {
|
||||
select {
|
||||
case status := <-exited:
|
||||
if status != 0 {
|
||||
t.Errorf("rproxy's exit status %d, want 0; output:\n%s", status, out.text())
|
||||
t.Errorf(
|
||||
"rproxy's exit status %d, want 0; output:\n%s",
|
||||
status,
|
||||
out.text(),
|
||||
)
|
||||
}
|
||||
case <-time.After(waitLimit):
|
||||
t.Error("rproxy still running after being told to stop")
|
||||
@@ -94,7 +98,10 @@ func startRProxy(t *testing.T, backend, appURL string) (string, *output) {
|
||||
// startWAF runs waf with the settings in env, and returns
|
||||
// its address and URL, what it writes, and what stops it, which checks that it
|
||||
// stopped in order.
|
||||
func startWAF(t *testing.T, env map[string]string) (string, *output, func()) {
|
||||
func startWAF(
|
||||
t *testing.T,
|
||||
env map[string]string,
|
||||
) (string, *output, func()) {
|
||||
t.Helper()
|
||||
|
||||
ctx, stop := context.WithCancel(t.Context())
|
||||
@@ -113,7 +120,11 @@ func startWAF(t *testing.T, env map[string]string) (string, *output, func()) {
|
||||
select {
|
||||
case status := <-exited:
|
||||
if status != 0 {
|
||||
t.Fatalf("waf's exit status %d, want 0; output:\n%s", status, out.text())
|
||||
t.Fatalf(
|
||||
"waf's exit status %d, want 0; output:\n%s",
|
||||
status,
|
||||
out.text(),
|
||||
)
|
||||
}
|
||||
case <-time.After(waitLimit):
|
||||
t.Fatal("waf still running after being told to stop")
|
||||
@@ -341,7 +352,12 @@ func pipe(dst, src net.Conn) {
|
||||
// answersNormally reports whether a request to url from the client at from, as
|
||||
// X-Forwarded-For names it, gets the app's answer.
|
||||
func answersNormally(ctx context.Context, url, from string) bool {
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, http.NoBody)
|
||||
req, err := http.NewRequestWithContext(
|
||||
ctx,
|
||||
http.MethodGet,
|
||||
url,
|
||||
http.NoBody,
|
||||
)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
@@ -359,7 +375,8 @@ func answersNormally(ctx context.Context, url, from string) bool {
|
||||
body, err := io.ReadAll(res.Body)
|
||||
_ = res.Body.Close()
|
||||
|
||||
return err == nil && res.StatusCode == http.StatusOK && string(body) == greeting
|
||||
return err == nil && res.StatusCode == http.StatusOK &&
|
||||
string(body) == greeting
|
||||
}
|
||||
|
||||
// sendRaw sends request, as it is, to rproxy at site, and returns the status of
|
||||
@@ -412,9 +429,16 @@ func TestAChunkedBodyStaysABodyAtWAF(t *testing.T) {
|
||||
waf.ClientHeader + ": " + otherClient + "\r\n" +
|
||||
"X-Request-ID: " + smuggledID + "\r\n\r\n"
|
||||
|
||||
status := sendRaw(t, site, "POST /upload HTTP/1.1\r\nHost: site.example\r\n"+
|
||||
"X-Forwarded-For: "+placed+"\r\nTransfer-Encoding: chunked\r\n\r\n"+
|
||||
strconv.FormatInt(int64(len(smuggled)), 16)+"\r\n"+smuggled+"\r\n0\r\n\r\n")
|
||||
status := sendRaw(
|
||||
t,
|
||||
site,
|
||||
"POST /upload HTTP/1.1\r\nHost: site.example\r\n"+
|
||||
"X-Forwarded-For: "+placed+"\r\nTransfer-Encoding: chunked\r\n\r\n"+
|
||||
strconv.FormatInt(
|
||||
int64(len(smuggled)),
|
||||
16,
|
||||
)+"\r\n"+smuggled+"\r\n0\r\n\r\n",
|
||||
)
|
||||
if status != http.StatusOK {
|
||||
t.Errorf("status %d, want the app's 200", status)
|
||||
}
|
||||
@@ -443,8 +467,12 @@ func TestATargetThatCannotGoToWAFIsRefusedForABannedClient(t *testing.T) {
|
||||
|
||||
wantStatus(t, site+bannedProbe, placed, http.StatusForbidden)
|
||||
|
||||
status := sendRaw(t, site, "GET x:admin HTTP/1.1\r\nHost: site.example\r\n"+
|
||||
"X-Forwarded-For: "+placed+"\r\n\r\n")
|
||||
status := sendRaw(
|
||||
t,
|
||||
site,
|
||||
"GET x:admin HTTP/1.1\r\nHost: site.example\r\n"+
|
||||
"X-Forwarded-For: "+placed+"\r\n\r\n",
|
||||
)
|
||||
if status != http.StatusBadRequest {
|
||||
t.Errorf("status %d, want 400", status)
|
||||
}
|
||||
@@ -470,7 +498,8 @@ func TestAClientWithAZoneIsTheClientWithout(t *testing.T) {
|
||||
wantStatus(t, site+"/", "2001:db8::1", http.StatusForbidden)
|
||||
|
||||
line := out.line(t, "path", bannedProbe)
|
||||
if line["client_ip"] != "2001:db8::1" || line["default_disposition"] != nil {
|
||||
if line["client_ip"] != "2001:db8::1" ||
|
||||
line["default_disposition"] != nil {
|
||||
t.Errorf("rproxy's line is %v", line)
|
||||
}
|
||||
}
|
||||
@@ -495,7 +524,10 @@ func TestAStatusWAFDoesNotTakeIsReportedAs599(t *testing.T) {
|
||||
|
||||
line := out.line(t, "path", "/")
|
||||
if line["status"] != float64(status) {
|
||||
t.Errorf("rproxy's line is %v, want the status the visitor got", line)
|
||||
t.Errorf(
|
||||
"rproxy's line is %v, want the status the visitor got",
|
||||
line,
|
||||
)
|
||||
}
|
||||
|
||||
id, _ := line["request_id"].(string)
|
||||
@@ -519,7 +551,8 @@ func startRProxyProcess(t *testing.T, env ...string) (string, func()) {
|
||||
}
|
||||
|
||||
out := &output{}
|
||||
cmd := exec.CommandContext(t.Context(), binary) //nolint:gosec // this test binary
|
||||
//nolint:gosec // this test binary
|
||||
cmd := exec.CommandContext(t.Context(), binary)
|
||||
cmd.Stdout = out
|
||||
|
||||
cmd.Env = append(os.Environ(),
|
||||
@@ -540,7 +573,11 @@ func startRProxyProcess(t *testing.T, env ...string) (string, func()) {
|
||||
select {
|
||||
case status := <-exited:
|
||||
if status != 0 {
|
||||
t.Errorf("exit status %d, want 0; output:\n%s", status, out.text())
|
||||
t.Errorf(
|
||||
"exit status %d, want 0; output:\n%s",
|
||||
status,
|
||||
out.text(),
|
||||
)
|
||||
}
|
||||
case <-time.After(waitLimit):
|
||||
t.Error("still running after being told to stop")
|
||||
@@ -587,7 +624,11 @@ func TestRProxyAsksAWAFThatSpeaksHTTP2OverHTTP1(t *testing.T) {
|
||||
"Connection": "Connection: anything\r\n",
|
||||
"a WebSocket upgrade": "Connection: Upgrade\r\nUpgrade: websocket\r\n",
|
||||
} {
|
||||
status := sendRaw(t, addr, "GET / HTTP/1.1\r\nHost: site.example\r\n"+headers+"\r\n")
|
||||
status := sendRaw(
|
||||
t,
|
||||
addr,
|
||||
"GET / HTTP/1.1\r\nHost: site.example\r\n"+headers+"\r\n",
|
||||
)
|
||||
if status != http.StatusForbidden {
|
||||
t.Errorf("with %s: status %d, want waf's 403", name, status)
|
||||
}
|
||||
@@ -595,7 +636,11 @@ func TestRProxyAsksAWAFThatSpeaksHTTP2OverHTTP1(t *testing.T) {
|
||||
select {
|
||||
case protocol := <-protocols:
|
||||
if protocol != "HTTP/1.1" {
|
||||
t.Errorf("with %s: asked over %s, want HTTP/1.1", name, protocol)
|
||||
t.Errorf(
|
||||
"with %s: asked over %s, want HTTP/1.1",
|
||||
name,
|
||||
protocol,
|
||||
)
|
||||
}
|
||||
case <-time.After(waitLimit):
|
||||
t.Errorf("with %s: waf was not asked", name)
|
||||
@@ -616,7 +661,11 @@ func TestRProxyProcessLinesNameTheHostAndComeAtInfo(t *testing.T) {
|
||||
|
||||
line := out.line(t, "msg", "starting")
|
||||
if line["instance"] != hostname || line["level"] != "INFO" {
|
||||
t.Errorf("rproxy's line is %v, want instance %s at INFO", line, hostname)
|
||||
t.Errorf(
|
||||
"rproxy's line is %v, want instance %s at INFO",
|
||||
line,
|
||||
hostname,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -681,7 +730,11 @@ func TestRProxyStoppingWaitsForAReportBeingSent(t *testing.T) {
|
||||
select {
|
||||
case status := <-exited:
|
||||
if status != 0 {
|
||||
t.Errorf("rproxy's exit status %d, want 0; output:\n%s", status, out.text())
|
||||
t.Errorf(
|
||||
"rproxy's exit status %d, want 0; output:\n%s",
|
||||
status,
|
||||
out.text(),
|
||||
)
|
||||
}
|
||||
case <-time.After(waitLimit):
|
||||
t.Error("rproxy still running, the report having been answered")
|
||||
@@ -755,7 +808,11 @@ func TestRProxyStoppingCutsOffARequestAfterFiveSeconds(t *testing.T) {
|
||||
}()
|
||||
|
||||
addr, _ := out.lineBeforeExit(t, "starting", exited)["address"].(string)
|
||||
conn := sendAndKeepOpen(t, addr, "GET / HTTP/1.1\r\nHost: site.example\r\n\r\n")
|
||||
conn := sendAndKeepOpen(
|
||||
t,
|
||||
addr,
|
||||
"GET / HTTP/1.1\r\nHost: site.example\r\n\r\n",
|
||||
)
|
||||
|
||||
select {
|
||||
case <-asked:
|
||||
@@ -779,7 +836,11 @@ func TestRProxyStoppingCutsOffARequestAfterFiveSeconds(t *testing.T) {
|
||||
select {
|
||||
case status := <-exited:
|
||||
if status != 0 {
|
||||
t.Errorf("rproxy's exit status %d, want 0; output:\n%s", status, out.text())
|
||||
t.Errorf(
|
||||
"rproxy's exit status %d, want 0; output:\n%s",
|
||||
status,
|
||||
out.text(),
|
||||
)
|
||||
}
|
||||
case <-time.After(waitLimit):
|
||||
t.Error("rproxy still running after the cut-off")
|
||||
@@ -814,7 +875,11 @@ func TestRProxyInvalidSettingStopsTheStart(t *testing.T) {
|
||||
message, _ := line["error"].(string)
|
||||
|
||||
if !strings.HasPrefix(message, tc.setting+": ") {
|
||||
t.Errorf("start refused with %v, want it to name %s", line, tc.setting)
|
||||
t.Errorf(
|
||||
"start refused with %v, want it to name %s",
|
||||
line,
|
||||
tc.setting,
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -823,7 +888,11 @@ func TestRProxyInvalidSettingStopsTheStart(t *testing.T) {
|
||||
func TestRProxyAddressInUseStopsTheStart(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
taken, err := (&net.ListenConfig{}).Listen(t.Context(), "tcp", localhost+":0")
|
||||
taken, err := (&net.ListenConfig{}).Listen(
|
||||
t.Context(),
|
||||
"tcp",
|
||||
localhost+":0",
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("listen: %v", err)
|
||||
}
|
||||
|
||||
+80
-25
@@ -79,7 +79,11 @@ func Main(version string) int {
|
||||
syscall.SIGTERM, os.Interrupt)
|
||||
defer stop()
|
||||
|
||||
params := Params{Version: version, LookupEnv: os.LookupEnv, Stdout: os.Stdout}
|
||||
params := Params{
|
||||
Version: version,
|
||||
LookupEnv: os.LookupEnv,
|
||||
Stdout: os.Stdout,
|
||||
}
|
||||
|
||||
switch args[0] {
|
||||
case "rproxy":
|
||||
@@ -111,9 +115,7 @@ func RunWAF(ctx context.Context, params Params) int {
|
||||
|
||||
cfg, err := config.FromEnvironment(params.LookupEnv)
|
||||
if err != nil {
|
||||
processLog.Error("invalid setting", "error", err.Error())
|
||||
|
||||
return 1
|
||||
return cannotStart(processLog, "invalid setting", err)
|
||||
}
|
||||
|
||||
// While SWW_LOG_REMOTE_URL is set, every line on stdout from here on
|
||||
@@ -127,13 +129,38 @@ func RunWAF(ctx context.Context, params Params) int {
|
||||
stdout = io.MultiWriter(params.Stdout, remote)
|
||||
}
|
||||
|
||||
processLog = requestlog.NewProcessLogger(stdout, cfg.InstanceName, cfg.LogLevel)
|
||||
processLog = requestlog.NewProcessLogger(
|
||||
stdout,
|
||||
cfg.InstanceName,
|
||||
cfg.LogLevel,
|
||||
)
|
||||
|
||||
if remote != nil {
|
||||
stopSending := startSending(ctx, remote, processLog)
|
||||
defer stopSending()
|
||||
}
|
||||
|
||||
return runWAFWithSettings(
|
||||
ctx,
|
||||
params.Version,
|
||||
cfg,
|
||||
stdout,
|
||||
remote,
|
||||
processLog,
|
||||
)
|
||||
}
|
||||
|
||||
// runWAFWithSettings is the rest of RunWAF once the settings are read and
|
||||
// the process log goes where they say. remote is nil unless
|
||||
// SWW_LOG_REMOTE_URL is set.
|
||||
func runWAFWithSettings(
|
||||
ctx context.Context,
|
||||
version string,
|
||||
cfg *config.Config,
|
||||
stdout io.Writer,
|
||||
remote *remotelog.Sender,
|
||||
processLog *slog.Logger,
|
||||
) int {
|
||||
// The state files and the alerts give times in UTC.
|
||||
now := func() time.Time { return time.Now().UTC() }
|
||||
|
||||
@@ -146,23 +173,25 @@ func RunWAF(ctx context.Context, params Params) int {
|
||||
Alerts: alertQueue,
|
||||
})
|
||||
if err != nil {
|
||||
processLog.Error("cannot use the rule files", "error", err.Error())
|
||||
|
||||
return 1
|
||||
return cannotStart(processLog, "cannot use the rule files", err)
|
||||
}
|
||||
|
||||
crs, err := waf.NewCoreRuleSet(cfg)
|
||||
if err != nil {
|
||||
processLog.Error("cannot use the Core Rule Set", "error", err.Error())
|
||||
|
||||
return 1
|
||||
return cannotStart(processLog, "cannot use the Core Rule Set", err)
|
||||
}
|
||||
|
||||
server, err := newServer(cfg, stdout, processLog, now, ruleFiles, alertQueue, crs)
|
||||
server, err := newServer(
|
||||
cfg,
|
||||
stdout,
|
||||
processLog,
|
||||
now,
|
||||
ruleFiles,
|
||||
alertQueue,
|
||||
crs,
|
||||
)
|
||||
if err != nil {
|
||||
processLog.Error("cannot use the lookup database", "error", err.Error())
|
||||
|
||||
return 1
|
||||
return cannotStart(processLog, "cannot use the lookup database", err)
|
||||
}
|
||||
|
||||
if remote != nil {
|
||||
@@ -171,24 +200,43 @@ func RunWAF(ctx context.Context, params Params) int {
|
||||
|
||||
files, err := loadStateFiles(cfg, server, alertQueue, now, processLog)
|
||||
if err != nil {
|
||||
processLog.Error("cannot use the state and cache files", "error", err.Error())
|
||||
|
||||
return 1
|
||||
return cannotStart(
|
||||
processLog,
|
||||
"cannot use the state and cache files",
|
||||
err,
|
||||
)
|
||||
}
|
||||
|
||||
listener, err := (&net.ListenConfig{}).Listen(ctx, "tcp", cfg.ListenAddr)
|
||||
if err != nil {
|
||||
processLog.Error("cannot listen on SWW_LISTEN_ADDR", "error", err.Error())
|
||||
|
||||
return 1
|
||||
return cannotStart(
|
||||
processLog,
|
||||
"cannot listen on SWW_LISTEN_ADDR",
|
||||
err,
|
||||
)
|
||||
}
|
||||
|
||||
processLog.Info("starting",
|
||||
"version", params.Version,
|
||||
"version", version,
|
||||
"address", listener.Addr().String(),
|
||||
"settings", cfg)
|
||||
|
||||
return serve(ctx, server, listener, files, ruleFiles, alertQueue, processLog)
|
||||
return serve(
|
||||
ctx,
|
||||
server,
|
||||
listener,
|
||||
files,
|
||||
ruleFiles,
|
||||
alertQueue,
|
||||
processLog,
|
||||
)
|
||||
}
|
||||
|
||||
// cannotStart logs why waf cannot start, and returns its exit status.
|
||||
func cannotStart(processLog *slog.Logger, message string, err error) int {
|
||||
processLog.Error(message, "error", err.Error())
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
// newServer returns the server waf runs, with the metrics of the alerts,
|
||||
@@ -230,7 +278,10 @@ func newServer(
|
||||
server.Metrics.AddAlerts(alertQueue)
|
||||
|
||||
if lookupFile != nil {
|
||||
server.Metrics.AddLookupFile(lookupFile.LastRead, lookupFile.ReadFailures)
|
||||
server.Metrics.AddLookupFile(
|
||||
lookupFile.LastRead,
|
||||
lookupFile.ReadFailures,
|
||||
)
|
||||
}
|
||||
|
||||
return server, nil
|
||||
@@ -395,7 +446,11 @@ func serve(
|
||||
|
||||
err = files.WriteAll()
|
||||
if err != nil {
|
||||
processLog.Error("writing the state and cache files failed", "error", err.Error())
|
||||
processLog.Error(
|
||||
"writing the state and cache files failed",
|
||||
"error",
|
||||
err.Error(),
|
||||
)
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
@@ -22,7 +22,10 @@ func TestStopWaitsForTheSenderToFinish(t *testing.T) {
|
||||
synctest.Test(t, func(t *testing.T) {
|
||||
took := stopHeldSender(t, time.Second)
|
||||
if took != time.Second {
|
||||
t.Errorf("the stop took %s, want the second the sender took", took)
|
||||
t.Errorf(
|
||||
"the stop took %s, want the second the sender took",
|
||||
took,
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -59,7 +62,10 @@ func stopHeldSender(t *testing.T, release time.Duration) time.Duration {
|
||||
sender := remotelog.New(remotelog.Params{
|
||||
// No port is 65536, so each attempt to connect fails at once,
|
||||
// before it reaches the network.
|
||||
URL: &url.URL{Scheme: remotelog.SchemeTCP, Host: "127.0.0.1:65536"},
|
||||
URL: &url.URL{
|
||||
Scheme: remotelog.SchemeTCP,
|
||||
Host: "127.0.0.1:65536",
|
||||
},
|
||||
Buffer: 1,
|
||||
})
|
||||
|
||||
|
||||
+194
-63
@@ -111,8 +111,12 @@ func (o *output) lineBeforeExit(
|
||||
|
||||
select {
|
||||
case status := <-exited:
|
||||
t.Fatalf("exit status %d while waiting for a line with msg %q; output:\n%s",
|
||||
status, msg, o.text())
|
||||
t.Fatalf(
|
||||
"exit status %d while waiting for a line with msg %q; output:\n%s",
|
||||
status,
|
||||
msg,
|
||||
o.text(),
|
||||
)
|
||||
case <-time.After(pollInterval):
|
||||
}
|
||||
}
|
||||
@@ -227,7 +231,11 @@ func TestShortTokenStopsTheStartUnshown(t *testing.T) {
|
||||
func TestAddressInUseStopsTheStart(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
taken, err := (&net.ListenConfig{}).Listen(t.Context(), "tcp", localhost+":0")
|
||||
taken, err := (&net.ListenConfig{}).Listen(
|
||||
t.Context(),
|
||||
"tcp",
|
||||
localhost+":0",
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("listen: %v", err)
|
||||
}
|
||||
@@ -325,7 +333,11 @@ func TestLogLevelHoldsBackTheLessSevereProcessLines(t *testing.T) {
|
||||
select {
|
||||
case status := <-exited:
|
||||
if status != 0 {
|
||||
t.Fatalf("exit status %d, want 0; output:\n%s", status, out.text())
|
||||
t.Fatalf(
|
||||
"exit status %d, want 0; output:\n%s",
|
||||
status,
|
||||
out.text(),
|
||||
)
|
||||
}
|
||||
case <-time.After(waitLimit):
|
||||
t.Fatal("still running after being told to stop")
|
||||
@@ -479,7 +491,14 @@ func TestBanAddedAndLiftedByEditingBansJSON(t *testing.T) {
|
||||
runUntilStopped(t, env, func(url string) {
|
||||
path := filepath.Join(dir, "bans.json")
|
||||
|
||||
saveUntilAnswered(t, path, oneBan, url, "203.0.113.9", http.StatusForbidden)
|
||||
saveUntilAnswered(
|
||||
t,
|
||||
path,
|
||||
oneBan,
|
||||
url,
|
||||
"203.0.113.9",
|
||||
http.StatusForbidden,
|
||||
)
|
||||
wantStatus(t, url, "198.51.100.7", http.StatusOK)
|
||||
saveUntilAnswered(t, path, noBan, url, "203.0.113.9", http.StatusOK)
|
||||
})
|
||||
@@ -568,12 +587,20 @@ func TestRuleFileThatDoesNotParseStopsTheStart(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
path := filepath.Join(dir, "00-default.rules")
|
||||
|
||||
err := os.WriteFile(path, []byte("# probes\nenv-file path bann ^/\\.env$\n"), 0o600)
|
||||
err := os.WriteFile(
|
||||
path,
|
||||
[]byte("# probes\nenv-file path bann ^/\\.env$\n"),
|
||||
0o600,
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("write the rule file: %v", err)
|
||||
}
|
||||
|
||||
wantRulesRefused(t, dir, path+`, line 2: the action "bann" is not log, block or ban`)
|
||||
wantRulesRefused(
|
||||
t,
|
||||
dir,
|
||||
path+`, line 2: the action "bann" is not log, block or ban`,
|
||||
)
|
||||
}
|
||||
|
||||
func TestRulesDirThatDoesNotExistStopsTheStart(t *testing.T) {
|
||||
@@ -585,7 +612,9 @@ func TestRulesDirThatDoesNotExistStopsTheStart(t *testing.T) {
|
||||
": no such file or directory")
|
||||
}
|
||||
|
||||
func TestCoreRuleSetExclusionsFileThatCannotBeReadStopsTheStart(t *testing.T) {
|
||||
func TestCoreRuleSetExclusionsFileThatCannotBeReadStopsTheStart(
|
||||
t *testing.T,
|
||||
) {
|
||||
t.Parallel()
|
||||
|
||||
path := filepath.Join(t.TempDir(), "crs-exclusions.conf")
|
||||
@@ -686,23 +715,38 @@ func TestLookupDatabaseReplacedWhileRunningTakesEffect(t *testing.T) {
|
||||
}
|
||||
|
||||
// One that cannot be read leaves the file read before in use.
|
||||
err := os.WriteFile(replacement, []byte("not a lookup database\n"), 0o600)
|
||||
err := os.WriteFile(
|
||||
replacement,
|
||||
[]byte("not a lookup database\n"),
|
||||
0o600,
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("write %s: %v", replacement, err)
|
||||
}
|
||||
|
||||
rename(t, replacement, path)
|
||||
|
||||
metrics := metricsWith(t, url+"_sww/metrics", token,
|
||||
`sww_lookup_database_read_failures_total{instance="fsn1app1/blog"} 1`)
|
||||
lastRead = seriesValue(t, metrics,
|
||||
`sww_lookup_database_last_read_timestamp_seconds{instance="fsn1app1/blog"}`)
|
||||
metrics := metricsWith(
|
||||
t,
|
||||
url+"_sww/metrics",
|
||||
token,
|
||||
`sww_lookup_database_read_failures_total{instance="fsn1app1/blog"} 1`,
|
||||
)
|
||||
lastRead = seriesValue(
|
||||
t,
|
||||
metrics,
|
||||
`sww_lookup_database_last_read_timestamp_seconds{instance="fsn1app1/blog"}`,
|
||||
)
|
||||
|
||||
wantStatus(t, url, placed, http.StatusOK)
|
||||
})
|
||||
|
||||
if lastRead < float64(began.Unix()) || lastRead > float64(time.Now().Unix()) {
|
||||
t.Errorf("the lookup database was last read at %v, want a time in the test", lastRead)
|
||||
if lastRead < float64(began.Unix()) ||
|
||||
lastRead > float64(time.Now().Unix()) {
|
||||
t.Errorf(
|
||||
"the lookup database was last read at %v, want a time in the test",
|
||||
lastRead,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -776,8 +820,8 @@ func TestBlocklistTriesAndCopiesKeptInListsJSONAcrossRestarts(t *testing.T) {
|
||||
})
|
||||
wantDeniedByList(t, out.line(t, "action", "client_denied"), dropURL)
|
||||
|
||||
if fetches := torFetches.Load(); fetches != 1 {
|
||||
t.Errorf("tor.txt fetched %d times, want once, before the restart", fetches)
|
||||
if n := torFetches.Load(); n != 1 {
|
||||
t.Errorf("tor.txt fetched %d times before the restart, want 1", n)
|
||||
}
|
||||
|
||||
// After another restart, with the server failing, the copy of drop.txt
|
||||
@@ -792,10 +836,10 @@ func TestBlocklistTriesAndCopiesKeptInListsJSONAcrossRestarts(t *testing.T) {
|
||||
|
||||
path := filepath.Join(cache, "lists.json")
|
||||
|
||||
kept, err := os.ReadFile(path) //nolint:gosec // a file in the test's directory
|
||||
//nolint:gosec // a file in the test's directory
|
||||
kept, err := os.ReadFile(path)
|
||||
if err != nil || !strings.Contains(string(kept), `"`+copyright+`"`) {
|
||||
t.Errorf("lists.json holds\n%s\nwant the copy with %q (%v)", kept, copyright,
|
||||
err)
|
||||
t.Errorf("lists.json holds\n%s\nwant %q (%v)", kept, copyright, err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -815,9 +859,12 @@ func TestCrowdSecDecisionListKeptInListsJSONAcrossARestart(t *testing.T) {
|
||||
case down.Load():
|
||||
w.WriteHeader(http.StatusServiceUnavailable)
|
||||
default:
|
||||
_, _ = io.WriteString(w, `[{"duration": "4h0m0s", "origin": "crowdsec", `+
|
||||
`"scenario": "crowdsecurity/http-probing", "scope": "Range", `+
|
||||
`"type": "ban", "value": "203.0.113.0/24"}]`)
|
||||
_, _ = io.WriteString(
|
||||
w,
|
||||
`[{"duration": "4h0m0s", "origin": "crowdsec", `+
|
||||
`"scenario": "crowdsecurity/http-probing", "scope": "Range", `+
|
||||
`"type": "ban", "value": "203.0.113.0/24"}]`,
|
||||
)
|
||||
}
|
||||
}))
|
||||
t.Cleanup(engine.Close)
|
||||
@@ -842,7 +889,11 @@ func TestCrowdSecDecisionListKeptInListsJSONAcrossARestart(t *testing.T) {
|
||||
ban := onlyBan(t, dir)
|
||||
if ban["netblock"] != placed+"/32" || ban["cause"] != "crowdsec" ||
|
||||
ban["reason"] != "CrowdSec's decision for crowdsecurity/http-probing" {
|
||||
t.Errorf("bans.json holds %v, want the ban for crowdsec on %s", ban, placed)
|
||||
t.Errorf(
|
||||
"bans.json holds %v, want the ban for crowdsec on %s",
|
||||
ban,
|
||||
placed,
|
||||
)
|
||||
}
|
||||
|
||||
// Restarted with the engine down, the copy kept in lists.json bans
|
||||
@@ -871,7 +922,10 @@ func TestCrowdSecDecisionListKeptInListsJSONAcrossARestart(t *testing.T) {
|
||||
}
|
||||
|
||||
if all := strings.Join(shown, "\n"); strings.Contains(all, bouncerKey) {
|
||||
t.Errorf("the key is shown in the output or the state and cache files:\n%s", all)
|
||||
t.Errorf(
|
||||
"the key is shown in the output or the state and cache files:\n%s",
|
||||
all,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -883,7 +937,11 @@ func wantDeniedByList(t *testing.T, line map[string]any, listURL string) {
|
||||
reputation, _ := line["reputation"].([]any)
|
||||
if line["action"] != "client_denied" || len(reputation) != 1 ||
|
||||
reputation[0] != listURL {
|
||||
t.Errorf("request log line %v, want one denied for %s", line, listURL)
|
||||
t.Errorf(
|
||||
"request log line %v, want one denied for %s",
|
||||
line,
|
||||
listURL,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -918,7 +976,11 @@ func TestLookupDatabaseThatCannotBeReadStopsTheStart(t *testing.T) {
|
||||
func TestEveryLineIsAlsoSentToTheRemoteLogEndpoint(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
endpoint, err := (&net.ListenConfig{}).Listen(t.Context(), "tcp", localhost+":0")
|
||||
endpoint, err := (&net.ListenConfig{}).Listen(
|
||||
t.Context(),
|
||||
"tcp",
|
||||
localhost+":0",
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("listen: %v", err)
|
||||
}
|
||||
@@ -973,7 +1035,11 @@ func TestStalledRemoteLogEndpointHoldsUpNoRequest(t *testing.T) {
|
||||
|
||||
// The endpoint takes connections and never answers, so the TLS
|
||||
// handshake of each waits on it, and no line is ever sent.
|
||||
endpoint, err := (&net.ListenConfig{}).Listen(t.Context(), "tcp", localhost+":0")
|
||||
endpoint, err := (&net.ListenConfig{}).Listen(
|
||||
t.Context(),
|
||||
"tcp",
|
||||
localhost+":0",
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("listen: %v", err)
|
||||
}
|
||||
@@ -1009,7 +1075,8 @@ func TestStalledRemoteLogEndpointHoldsUpNoRequest(t *testing.T) {
|
||||
|
||||
const dropped = "\nsww_remote_log_lines_dropped_total" +
|
||||
`{instance="fsn1app1/blog"} `
|
||||
if strings.Contains(metrics, dropped+"0\n") || !strings.Contains(metrics, dropped) {
|
||||
if strings.Contains(metrics, dropped+"0\n") ||
|
||||
!strings.Contains(metrics, dropped) {
|
||||
t.Errorf("no line dropped in the metrics:\n%s", metrics)
|
||||
}
|
||||
|
||||
@@ -1035,7 +1102,11 @@ func TestStalledRemoteLogEndpointHoldsUpNoRequest(t *testing.T) {
|
||||
// too.
|
||||
line := out.line(t, "msg", "starting")
|
||||
if line["instance"] != instance {
|
||||
t.Errorf("start logged with instance %v, want %s", line["instance"], instance)
|
||||
t.Errorf(
|
||||
"start logged with instance %v, want %s",
|
||||
line["instance"],
|
||||
instance,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1066,10 +1137,14 @@ func TestBanIsAlertedAndAnAlertNotSentIsKeptAcrossARestart(t *testing.T) {
|
||||
wantRefused(t, url+".env")
|
||||
|
||||
post := webhook.waitFor(t, "ban", true)
|
||||
if post.alert["client"] != localhost || post.alert["netblock"] != localhost+"/32" ||
|
||||
if post.alert["client"] != localhost ||
|
||||
post.alert["netblock"] != localhost+"/32" ||
|
||||
post.authorization != "Bearer "+adminSecret {
|
||||
t.Errorf("the webhook was sent %v, with Authorization %q", post.alert,
|
||||
post.authorization)
|
||||
t.Errorf(
|
||||
"the webhook was sent %v, with Authorization %q",
|
||||
post.alert,
|
||||
post.authorization,
|
||||
)
|
||||
}
|
||||
|
||||
// The webhook fails, so the alert for the ban made permanent by the
|
||||
@@ -1081,24 +1156,7 @@ func TestBanIsAlertedAndAnAlertNotSentIsKeptAcrossARestart(t *testing.T) {
|
||||
|
||||
// alerts.json keeps it as sww stops, and once started again,
|
||||
// sww sends it.
|
||||
var file struct {
|
||||
Waiting map[string][]struct {
|
||||
Event string `json:"event"`
|
||||
} `json:"waiting"`
|
||||
}
|
||||
|
||||
path := filepath.Join(dir, "alerts.json")
|
||||
|
||||
data, err := os.ReadFile(path) //nolint:gosec // a file in the test's directory
|
||||
if err == nil {
|
||||
err = json.Unmarshal(data, &file)
|
||||
}
|
||||
|
||||
waiting := file.Waiting["webhook"]
|
||||
if err != nil || len(waiting) != 1 || waiting[0].Event != "permanent_ban" {
|
||||
t.Fatalf("alerts.json holds %s (%v), want the permanent_ban alert waiting for "+
|
||||
"the webhook", data, err)
|
||||
}
|
||||
wantPermanentBanAlertWaiting(t, dir)
|
||||
|
||||
// It counts the alert sent in the metrics, read here from a client the
|
||||
// ban does not cover.
|
||||
@@ -1130,6 +1188,37 @@ func TestBanIsAlertedAndAnAlertNotSentIsKeptAcrossARestart(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
// wantPermanentBanAlertWaiting checks that alerts.json in dir holds one
|
||||
// alert waiting for the webhook, the permanent_ban alert.
|
||||
func wantPermanentBanAlertWaiting(t *testing.T, dir string) {
|
||||
t.Helper()
|
||||
|
||||
var file struct {
|
||||
Waiting map[string][]struct {
|
||||
Event string `json:"event"`
|
||||
} `json:"waiting"`
|
||||
}
|
||||
|
||||
path := filepath.Join(dir, "alerts.json")
|
||||
|
||||
//nolint:gosec // a file in the test's directory
|
||||
data, err := os.ReadFile(path)
|
||||
if err == nil {
|
||||
err = json.Unmarshal(data, &file)
|
||||
}
|
||||
|
||||
waiting := file.Waiting["webhook"]
|
||||
if err != nil || len(waiting) != 1 ||
|
||||
waiting[0].Event != "permanent_ban" {
|
||||
t.Fatalf(
|
||||
"alerts.json holds %s (%v), want the permanent_ban alert waiting for "+
|
||||
"the webhook",
|
||||
data,
|
||||
err,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBanIsAlertedToSlackAndNtfy(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
@@ -1167,7 +1256,8 @@ func TestBanIsAlertedToSlackAndNtfy(t *testing.T) {
|
||||
slackPost := slack.firstPost(t)
|
||||
err := json.Unmarshal([]byte(slackPost.body), &message)
|
||||
|
||||
if err != nil || !strings.HasPrefix(message.Text, "*fsn1app1/blog: ban*\n") ||
|
||||
if err != nil ||
|
||||
!strings.HasPrefix(message.Text, "*fsn1app1/blog: ban*\n") ||
|
||||
!strings.Contains(message.Text, "\nclient: "+client+"\n") {
|
||||
t.Errorf("Slack was sent %s", slackPost.body)
|
||||
}
|
||||
@@ -1202,14 +1292,22 @@ func TestStateFileThatDoesNotParseStopsTheStart(t *testing.T) {
|
||||
|
||||
dir := t.TempDir()
|
||||
|
||||
err := os.WriteFile(filepath.Join(dir, "bans.json"), []byte("{\n"), 0o600)
|
||||
err := os.WriteFile(
|
||||
filepath.Join(dir, "bans.json"),
|
||||
[]byte("{\n"),
|
||||
0o600,
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("write bans.json: %v", err)
|
||||
}
|
||||
|
||||
// The file ends at the newline that is the second byte of its first
|
||||
// line.
|
||||
wantStartRefused(t, dir, filepath.Join(dir, "bans.json")+", line 1, column 2: ")
|
||||
wantStartRefused(
|
||||
t,
|
||||
dir,
|
||||
filepath.Join(dir, "bans.json")+", line 1, column 2: ",
|
||||
)
|
||||
}
|
||||
|
||||
func TestUnwritableStateDirStopsTheStart(t *testing.T) {
|
||||
@@ -1264,7 +1362,11 @@ func wantStartRefused(t *testing.T, dir, want string) {
|
||||
message, _ := line["error"].(string)
|
||||
|
||||
if !strings.HasPrefix(message, want) {
|
||||
t.Errorf("start refused with %q, want an error starting %q", message, want)
|
||||
t.Errorf(
|
||||
"start refused with %q, want an error starting %q",
|
||||
message,
|
||||
want,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1329,7 +1431,11 @@ func runUntilStopped(
|
||||
select {
|
||||
case status := <-exited:
|
||||
if status != 0 {
|
||||
t.Fatalf("exit status %d, want 0; output:\n%s", status, out.text())
|
||||
t.Fatalf(
|
||||
"exit status %d, want 0; output:\n%s",
|
||||
status,
|
||||
out.text(),
|
||||
)
|
||||
}
|
||||
case <-time.After(waitLimit):
|
||||
t.Fatal("still running after being told to stop")
|
||||
@@ -1371,7 +1477,12 @@ func wantStartingLine(t *testing.T, line map[string]any, dir string) {
|
||||
|
||||
for name, value := range want {
|
||||
if settings[name] != value {
|
||||
t.Errorf("starting line gives %s=%v, want %v", name, settings[name], value)
|
||||
t.Errorf(
|
||||
"starting line gives %s=%v, want %v",
|
||||
name,
|
||||
settings[name],
|
||||
value,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1411,7 +1522,11 @@ func messages(t *testing.T, received string) []string {
|
||||
|
||||
_, message, ok := strings.Cut(record, header)
|
||||
if !ok || !strings.HasPrefix(record, "<134>1 ") {
|
||||
t.Fatalf("record %q, want priority <134> and header %q", record, header)
|
||||
t.Fatalf(
|
||||
"record %q, want priority <134> and header %q",
|
||||
record,
|
||||
header,
|
||||
)
|
||||
}
|
||||
|
||||
found = append(found, message+"\n")
|
||||
@@ -1476,7 +1591,10 @@ func seriesValue(t *testing.T, metrics, series string) float64 {
|
||||
t.Helper()
|
||||
|
||||
for line := range strings.Lines(metrics) {
|
||||
value, found := strings.CutPrefix(strings.TrimSpace(line), series+" ")
|
||||
value, found := strings.CutPrefix(
|
||||
strings.TrimSpace(line),
|
||||
series+" ",
|
||||
)
|
||||
if !found {
|
||||
continue
|
||||
}
|
||||
@@ -1510,7 +1628,11 @@ func writeLookupDatabase(t *testing.T, path, country string) {
|
||||
t.Helper()
|
||||
|
||||
lookuptest.Write(t, path, map[string]lookuptest.Network{
|
||||
placed + "/32": {ASN: "AS64496", ASName: "Example Net", Country: country},
|
||||
placed + "/32": {
|
||||
ASN: "AS64496",
|
||||
ASName: "Example Net",
|
||||
Country: country,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1548,7 +1670,8 @@ func onlyBan(t *testing.T, dir string) map[string]any {
|
||||
|
||||
path := filepath.Join(dir, "bans.json")
|
||||
|
||||
data, err := os.ReadFile(path) //nolint:gosec // a file in the test's directory
|
||||
//nolint:gosec // a file in the test's directory
|
||||
data, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
t.Fatalf("read bans.json: %v", err)
|
||||
}
|
||||
@@ -1590,7 +1713,11 @@ func wantStatus(t *testing.T, url, from string, status int) {
|
||||
// request, since sww may not watch its directory yet when it is
|
||||
// first written. It waits as long as that takes, so that a slow test
|
||||
// process cannot fail the test.
|
||||
func saveUntilAnswered(t *testing.T, path, content, url, from string, status int) {
|
||||
func saveUntilAnswered(
|
||||
t *testing.T,
|
||||
path, content, url, from string,
|
||||
status int,
|
||||
) {
|
||||
t.Helper()
|
||||
|
||||
for {
|
||||
@@ -1722,7 +1849,11 @@ func startWebhook(t *testing.T) *webhook {
|
||||
// waitFor waits until the webhook has been sent an alert for event that
|
||||
// it took, or, unless answered, failed, and returns it. It waits as long
|
||||
// as that takes, so that a slow test process cannot fail the test.
|
||||
func (w *webhook) waitFor(t *testing.T, event string, answered bool) webhookPost {
|
||||
func (w *webhook) waitFor(
|
||||
t *testing.T,
|
||||
event string,
|
||||
answered bool,
|
||||
) webhookPost {
|
||||
t.Helper()
|
||||
|
||||
for {
|
||||
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
"syscall"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
// The time zone database, so that the process TestMainRunsWAF starts
|
||||
// finds the zone TZ names on any host.
|
||||
_ "time/tzdata"
|
||||
@@ -85,7 +86,8 @@ func TestMainRunsWAF(t *testing.T) {
|
||||
|
||||
dir := t.TempDir()
|
||||
out := &output{}
|
||||
cmd := exec.CommandContext(t.Context(), binary) //nolint:gosec // this test binary
|
||||
//nolint:gosec // this test binary
|
||||
cmd := exec.CommandContext(t.Context(), binary)
|
||||
cmd.Stdout = out
|
||||
|
||||
cmd.Env = append(os.Environ(),
|
||||
@@ -112,7 +114,11 @@ func TestMainRunsWAF(t *testing.T) {
|
||||
select {
|
||||
case status := <-exited:
|
||||
if status != 0 {
|
||||
t.Fatalf("exit status %d, want 0; output:\n%s", status, out.text())
|
||||
t.Fatalf(
|
||||
"exit status %d, want 0; output:\n%s",
|
||||
status,
|
||||
out.text(),
|
||||
)
|
||||
}
|
||||
case <-time.After(waitLimit):
|
||||
t.Fatal("still running after being told to stop")
|
||||
@@ -123,7 +129,8 @@ func TestMainRunsWAF(t *testing.T) {
|
||||
|
||||
path := filepath.Join(dir, "clients.json")
|
||||
|
||||
clients, err := os.ReadFile(path) //nolint:gosec // a file in the test's directory
|
||||
//nolint:gosec // a file in the test's directory
|
||||
clients, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
t.Fatalf("read clients.json: %v", err)
|
||||
}
|
||||
@@ -181,7 +188,11 @@ func TestMainWithoutACommandItKnowsPrintsTheCommands(t *testing.T) {
|
||||
|
||||
for _, name := range []string{"rproxy", wafCommand, "healthcheck"} {
|
||||
if !strings.Contains(stderr.String(), name) {
|
||||
t.Errorf("stderr %q does not name %s", stderr.String(), name)
|
||||
t.Errorf(
|
||||
"stderr %q does not name %s",
|
||||
stderr.String(),
|
||||
name,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -219,8 +230,13 @@ func ask(t *testing.T, addr, path string, status int, disposition string) {
|
||||
|
||||
if res.StatusCode != status ||
|
||||
res.Header.Get(waf.DispositionHeader) != disposition {
|
||||
t.Errorf("answered %d with disposition %q, want %d with %q", res.StatusCode,
|
||||
res.Header.Get(waf.DispositionHeader), status, disposition)
|
||||
t.Errorf(
|
||||
"answered %d with disposition %q, want %d with %q",
|
||||
res.StatusCode,
|
||||
res.Header.Get(waf.DispositionHeader),
|
||||
status,
|
||||
disposition,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -245,7 +261,11 @@ func runWAF(t *testing.T, env map[string]string, use func(addr string)) {
|
||||
select {
|
||||
case status := <-exited:
|
||||
if status != 0 {
|
||||
t.Fatalf("exit status %d, want 0; output:\n%s", status, out.text())
|
||||
t.Fatalf(
|
||||
"exit status %d, want 0; output:\n%s",
|
||||
status,
|
||||
out.text(),
|
||||
)
|
||||
}
|
||||
case <-time.After(waitLimit):
|
||||
t.Fatal("still running after being told to stop")
|
||||
|
||||
Reference in new issue
Block a user