Format Go with gofmt, then golines -m 77 (closes #215)
check / check (push) Waiting to run

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:
sneak committed 2026-11-11 14:50:46 +00:00
1 parent f9bec5146b
commit a8b24a843b
117 files changed
+9441 -2670

No files matched your search

+55 -13
View File
@@ -63,7 +63,9 @@ const escapeLength = 3
var (
// ruleLine is a rule: four fields separated by spaces or tabs, of
// which the fourth, the regex, runs to the end of the line.
ruleLine = regexp.MustCompile(`^([^ \t]+)[ \t]+([^ \t]+)[ \t]+([^ \t]+)[ \t]+(.+)$`)
ruleLine = regexp.MustCompile(
`^([^ \t]+)[ \t]+([^ \t]+)[ \t]+([^ \t]+)[ \t]+(.+)$`,
)
// idChars are the characters of a rule's id.
idChars = regexp.MustCompile(`^[A-Za-z0-9_-]+$`)
)
@@ -74,7 +76,8 @@ var (
"separated by spaces or tabs")
errNotID = errors.New("is not an id of letters, digits, - and _")
errNotTarget = errors.New(
"is not path, query, uri, method, host, user_agent, referer or header:<Name>")
"is not path, query, uri, method, host, user_agent, referer or header:<Name>",
)
errNotHeaderName = errors.New(
"has a character after header: that no header name can have")
errHeaderTakenOut = errors.New(
@@ -281,7 +284,8 @@ func read(dir string) ([]Rule, string, error) {
for _, entry := range entries {
name := entry.Name()
if entry.IsDir() || strings.HasPrefix(name, ".") || filepath.Ext(name) != extension {
if entry.IsDir() || strings.HasPrefix(name, ".") ||
filepath.Ext(name) != extension {
continue
}
@@ -298,8 +302,13 @@ func read(dir string) ([]Rule, string, error) {
// readFile appends the rules of the rule file at path to rules. places
// are where each id read so far is, and gain those of the file.
func readFile(path string, rules []Rule, places map[string]string) ([]Rule, error) {
data, err := os.ReadFile(path) //nolint:gosec // a rule file, in SWW_RULES_DIR
func readFile(
path string,
rules []Rule,
places map[string]string,
) ([]Rule, error) {
//nolint:gosec // a rule file, in SWW_RULES_DIR
data, err := os.ReadFile(path)
if err != nil {
return nil, err
}
@@ -323,7 +332,13 @@ func readFile(path string, rules []Rule, places map[string]string) ([]Rule, erro
first, used := places[rule.ID]
if used {
return nil, fmt.Errorf("%s: the id %q %w %s", place, rule.ID, errUsedTwice, first)
return nil, fmt.Errorf(
"%s: the id %q %w %s",
place,
rule.ID,
errUsedTwice,
first,
)
}
places[rule.ID] = place
@@ -355,22 +370,42 @@ func parse(line string) (Rule, bool, error) {
case !idChars.MatchString(rule.ID):
return Rule{}, false, fmt.Errorf("the id %q %w", rule.ID, errNotID)
case !isTarget(rule.Target):
return Rule{}, false, fmt.Errorf("the target %q %w", rule.Target, errNotTarget)
return Rule{}, false, fmt.Errorf(
"the target %q %w",
rule.Target,
errNotTarget,
)
case isHeader && !config.IsHeaderName(headerName):
return Rule{}, false, fmt.Errorf("the target %q %w", rule.Target, errNotHeaderName)
return Rule{}, false, fmt.Errorf(
"the target %q %w",
rule.Target,
errNotHeaderName,
)
case strings.EqualFold(rule.Target, headerTarget+"Host"):
return Rule{}, false, fmt.Errorf(
"the target %q %w; the request's host is the target host",
rule.Target, errHeaderTakenOut)
case strings.EqualFold(rule.Target, headerTarget+"Transfer-Encoding"):
return Rule{}, false, fmt.Errorf("the target %q %w", rule.Target, errHeaderTakenOut)
return Rule{}, false, fmt.Errorf(
"the target %q %w",
rule.Target,
errHeaderTakenOut,
)
case !slices.Contains([]string{ActionLog, ActionBlock, ActionBan}, rule.Action):
return Rule{}, false, fmt.Errorf("the action %q %w", rule.Action, errNotAction)
return Rule{}, false, fmt.Errorf(
"the action %q %w",
rule.Action,
errNotAction,
)
}
regex, err := regexp.Compile(fields[4])
if err != nil {
return Rule{}, false, fmt.Errorf("the regex %w: %w", errNotRegex, err)
return Rule{}, false, fmt.Errorf(
"the regex %w: %w",
errNotRegex,
err,
)
}
rule.regex = regex
@@ -381,7 +416,13 @@ func parse(line string) (Rule, bool, error) {
// isTarget reports whether target is one a rule may have.
func isTarget(target string) bool {
switch target {
case pathTarget, "query", uriTarget, "method", "host", "user_agent", "referer":
case pathTarget,
"query",
uriTarget,
"method",
"host",
"user_agent",
"referer":
return true
}
@@ -397,7 +438,8 @@ func (rule Rule) matches(r *http.Request) bool {
target := value(rule.Target, r)
if rule.Target == pathTarget || rule.Target == uriTarget {
return rule.regex.MatchString(target) || rule.regex.MatchString(DecodeOnce(target))
return rule.regex.MatchString(target) ||
rule.regex.MatchString(DecodeOnce(target))
}
return rule.regex.MatchString(target)
+79 -18
View File
@@ -94,7 +94,13 @@ func TestEachTargetMatchesWhatItNames(t *testing.T) {
got := len(files.Match(r)) == 1
if got != tc.want {
t.Errorf("%s matches %s: %t, want %t", tc.rule, tc.uri, got, tc.want)
t.Errorf(
"%s matches %s: %t, want %t",
tc.rule,
tc.uri,
got,
tc.want,
)
}
})
}
@@ -123,7 +129,12 @@ func TestPathMatchedAsTheClientSentIt(t *testing.T) {
for _, target := range []string{
tc.sent, "http://app.example" + tc.sent, "http:" + tc.sent, "foo:" + tc.sent,
} {
r := httptest.NewRequestWithContext(t.Context(), http.MethodGet, target, nil)
r := httptest.NewRequestWithContext(
t.Context(),
http.MethodGet,
target,
nil,
)
wantMatched(t, files, r, "as-sent")
}
}
@@ -146,14 +157,20 @@ after path log ^/
wantMatched(t, files, get(t, "/page"), "every-path", "after")
// A ban rule ends it too.
files = load(t, ruleFiles{testFile: "ban path ban ^/\nlater path block ^/\n"})
files = load(
t,
ruleFiles{testFile: "ban path ban ^/\nlater path block ^/\n"},
)
wantMatched(t, files, get(t, "/"), "ban")
}
func TestSpacesAndTabsEndingALineAreNotPartOfItsRegex(t *testing.T) {
t.Parallel()
files := load(t, ruleFiles{testFile: "env-file path block ^/\\.env$ \t \n"})
files := load(
t,
ruleFiles{testFile: "env-file path block ^/\\.env$ \t \n"},
)
wantMatched(t, files, get(t, "/.env"), "env-file")
}
@@ -184,7 +201,10 @@ func TestFileWhoseNameStartsWithADotIsNotARuleFile(t *testing.T) {
// The lock file Emacs makes beside a file while it is edited: a link to
// nothing, which cannot be read.
err := os.Symlink("user@host.1234:1700000000", filepath.Join(dir, ".#"+firstFile))
err := os.Symlink(
"user@host.1234:1700000000",
filepath.Join(dir, ".#"+firstFile),
)
if err != nil {
t.Fatalf("symlink: %v", err)
}
@@ -276,7 +296,8 @@ func TestFaultStopsTheStartNamingTheFileAndLine(t *testing.T) {
dir := writeFiles(t, ruleFiles{"00-default.rules": tc.content})
path := filepath.Join(dir, "00-default.rules")
wantRefused(t, dir, path+", line "+strconv.Itoa(tc.line)+": "+tc.want)
want := path + ", line " + strconv.Itoa(tc.line) + ": " + tc.want
wantRefused(t, dir, want)
})
}
}
@@ -289,8 +310,12 @@ func TestIDUsedTwiceStopsTheStartNamingBothPlaces(t *testing.T) {
"50-b.rules": "other path log ^/b\nprobe path ban ^/c\n",
})
wantRefused(t, dir, filepath.Join(dir, "50-b.rules")+`, line 2: the id "probe" `+
"is already the id of the rule at "+filepath.Join(dir, "00-a.rules")+", line 1")
wantRefused(
t,
dir,
filepath.Join(dir, "50-b.rules")+`, line 2: the id "probe" `+
"is already the id of the rule at "+filepath.Join(dir, "00-a.rules")+", line 1",
)
}
func TestDirectoryThatDoesNotExistStopsTheStart(t *testing.T) {
@@ -305,7 +330,9 @@ func TestDirectoryThatDoesNotExistStopsTheStart(t *testing.T) {
func TestEmptyDirectoryLoadsNoRulesAndSaysSo(t *testing.T) {
t.Parallel()
params, lines := newParams(writeFiles(t, ruleFiles{"00-default.rules": "# none\n"}))
params, lines := newParams(
writeFiles(t, ruleFiles{"00-default.rules": "# none\n"}),
)
files, err := rules.Load(params)
if err != nil {
@@ -314,7 +341,11 @@ func TestEmptyDirectoryLoadsNoRulesAndSaysSo(t *testing.T) {
line := lines.waitFor(t, read)
if files.Len() != 0 || line["rules"] != 0.0 {
t.Errorf("%d rules loaded, and the log says %v, want none", files.Len(), line)
t.Errorf(
"%d rules loaded, and the log says %v, want none",
files.Len(),
line,
)
}
}
@@ -375,7 +406,12 @@ func TestBrokenEditKeepsTheRulesAsTheyWere(t *testing.T) {
// The edit's second line has an unknown action, so the rules stay as
// they were, the first line's earlier version included.
save(t, dir, firstFile, "first path block ^/edited\nsecond path bann ^/second\n")
save(
t,
dir,
firstFile,
"first path block ^/edited\nsecond path bann ^/second\n",
)
line := lines.waitFor(t, hasError)
want := filepath.Join(dir, firstFile) +
@@ -393,7 +429,11 @@ func TestBrokenEditKeepsTheRulesAsTheyWere(t *testing.T) {
if len(waiting) != 1 || waiting[0].Event != alerts.EventFileError ||
waiting[0].Reason != hasError || waiting[0].Detail["error"] != want ||
waiting[0].Detail["file"] != filepath.Join(dir, firstFile) {
t.Errorf("alerts waiting %+v, want one file_error alert for %q", waiting, want)
t.Errorf(
"alerts waiting %+v, want one file_error alert for %q",
waiting,
want,
)
}
}
wantFileError()
@@ -402,8 +442,16 @@ func TestBrokenEditKeepsTheRulesAsTheyWere(t *testing.T) {
wantMatched(t, files, get(t, "/second"))
// Once mended, the file is read again, and raises no alert.
save(t, dir, firstFile, "first path block ^/edited\nsecond path ban ^/second\n")
lines.waitUntil(t, func() bool { return len(files.Match(get(t, "/second"))) == 1 })
save(
t,
dir,
firstFile,
"first path block ^/edited\nsecond path ban ^/second\n",
)
lines.waitUntil(
t,
func() bool { return len(files.Match(get(t, "/second"))) == 1 },
)
wantMatched(t, files, get(t, "/edited"), "first")
wantFileError()
}
@@ -559,7 +607,10 @@ func load(t *testing.T, files ruleFiles) *rules.Files {
// watch loads the rules in dir, runs their Watch until the test ends, and
// waits until it watches the directory. It returns the alerts' queue as
// well.
func watch(t *testing.T, dir string) (*rules.Files, processLog, *alerts.Queue) {
func watch(
t *testing.T,
dir string,
) (*rules.Files, processLog, *alerts.Queue) {
t.Helper()
params, lines := newParams(dir)
@@ -611,21 +662,31 @@ func get(t *testing.T, target string) *http.Request {
// wantRefusedBy checks that a GET request for target with the user agent
// sent matches rule alone, and that rule refuses it.
func wantRefusedBy(t *testing.T, files *rules.Files, target, sent, rule string) {
func wantRefusedBy(
t *testing.T,
files *rules.Files,
target, sent, rule string,
) {
t.Helper()
r := get(t, target)
r.Header.Set(userAgent, sent)
matched := files.Match(r)
if len(matched) != 1 || matched[0].ID != rule || matched[0].Action == rules.ActionLog {
if len(matched) != 1 || matched[0].ID != rule ||
matched[0].Action == rules.ActionLog {
t.Errorf("%s from %q matched %v, want %s alone, refusing it", target,
sent, ids(matched), rule)
}
}
// wantMatched checks the ids of the rules r matches, in order.
func wantMatched(t *testing.T, files *rules.Files, r *http.Request, want ...string) {
func wantMatched(
t *testing.T,
files *rules.Files,
r *http.Request,
want ...string,
) {
t.Helper()
got := ids(files.Match(r))