Author SHA1 Message Date
sneak dfb44c5546 README rewritten from scratch so a newcomer can follow it (closes #154, closes #155)
check / check (push) Waiting to run
The old README opened with project history and one list of a hundred
settings. The new one leads with what smallwebwaf is, what it protects
against, how to build and deploy it, how it sits in front of the app,
what happens to a request, the settings most deployments touch, how to
check it works and how to develop it. The reference material, every
setting, bans, rule files, the Core Rule Set, the admin endpoints, the
request log, alerts, metrics, state files, lookups, reputation sources,
the image and gitea, moves to files under docs/, each linked from the
README. Every statement was checked against the code on next.

Model: fable-5-1
2026-10-22 21:02:38 +00:00
10 changed files with 1938 additions and 3233 deletions
+315 -2344
View File
File diff suppressed because it is too large Load Diff
+1597 -862
View File
File diff suppressed because it is too large Load Diff
+6 -5
View File
@@ -1,8 +1,8 @@
// Package alerts sends alerts on bans, on traffic over an anomaly
// threshold, on a source that fails and on a file with an error to each
// destination set: to the webhook
// SWWAF_ALERT_WEBHOOK_URL names, each as one JSON object, as "The JSON
// object" in docs/alerts.md describes, to the Slack incoming
// SWWAF_ALERT_WEBHOOK_URL names, each as one JSON object, as the "Alert
// webhook schema" section of SPEC.md describes, to the Slack incoming
// webhook SWWAF_ALERT_SLACK_WEBHOOK_URL names, as a message, and to the
// ntfy topic SWWAF_ALERT_NTFY_URL names. A repeat within
// SWWAF_ALERT_COOLDOWN is held back, and so is an alert past
@@ -149,10 +149,11 @@ type Params struct {
}
// Alert is one alert, as the webhook is sent it and alerts.json holds it,
// with the fields of "The JSON object" in docs/alerts.md. ASN, ASName and
// Country are, for a ban, the client's as the ban's notes give them.
// with the fields of the "Alert webhook schema" section of SPEC.md. ASN,
// ASName and Country are, for a ban, the client's as the ban's notes give
// them.
//
//nolint:tagliatelle // docs/alerts.md names the alert's fields in snake_case
//nolint:tagliatelle // SPEC.md's alert webhook schema names its fields in snake_case
type Alert struct {
Instance string `json:"instance"`
Time time.Time `json:"time"`
+2 -2
View File
@@ -1,8 +1,8 @@
// Package anomaly counts requests and bytes over a minute and an hour, per
// client, per surrounding netblock, per AS number, for the whole service
// and per named netblock, and raises an anomaly alert for a count over its
// threshold, as "Anomaly thresholds" under "Settings" in SPEC.md
// describes. It refuses and bans nothing. At most 20,000 counters
// threshold, as "Anomaly thresholds" under "Configuration surface" in
// SPEC.md describes. It refuses and bans nothing. At most 20,000 counters
// are kept, in memory, and written to alerts.json and read from it by the
// state package.
package anomaly
+3 -4
View File
@@ -1,7 +1,6 @@
// Package metrics keeps smallwebwaf's Prometheus metrics, as
// docs/metrics.md lists them, and serves them in the Prometheus text
// format, as the "Metrics endpoint" section of SPEC.md requires. No
// metric carries a client's address.
// Package metrics keeps smallwebwaf's Prometheus metrics, as the "Metrics
// endpoint" section of SPEC.md lists them, and serves them in the
// Prometheus text format. No metric carries a client's address.
package metrics
import (
+1 -1
View File
@@ -206,7 +206,7 @@ type Hit struct {
// Counts are a client's requests and bytes in the minute, the hour and
// the day that end at a request, that request's included.
//
//nolint:tagliatelle // docs/request-log.md names the fields in snake_case
//nolint:tagliatelle // SPEC.md's request log names its fields in snake_case
type Counts struct {
Minute float64 `json:"minute"`
Hour float64 `json:"hour"`
+3 -4
View File
@@ -1,9 +1,8 @@
// Package remotelog sends the lines smallwebwaf writes on stdout to the
// remote log endpoint, SWWAF_LOG_REMOTE_URL, as the "Request log" section
// of SPEC.md requires and "Sending the log to a syslog server" in
// docs/request-log.md describes: each line as the message of an RFC 5424
// syslog record, over UDP, TCP or TLS. Lines wait in a bounded buffer, so
// a slow or unreachable endpoint never holds up a request or stdout.
// of SPEC.md describes: each line as the message of an RFC 5424 syslog
// record, over UDP, TCP or TLS. Lines wait in a bounded buffer, so a slow
// or unreachable endpoint never holds up a request or stdout.
package remotelog
import (
+4 -3
View File
@@ -64,10 +64,11 @@ const LimitHitErrorBurst = "error_burst"
const timeLayout = "2006-01-02T15:04:05.000Z07:00"
// Line is one request's line in the request log. The field names, and
// their order, are those of docs/request-log.md. A field that may not
// apply to a request is left out of its line when it does not.
// their order, are those of the "Request log" section of SPEC.md. A field
// that may not apply to a request is left out of its line when it does
// not.
//
//nolint:tagliatelle // docs/request-log.md names the fields in snake_case
//nolint:tagliatelle // SPEC.md's request log names its fields in snake_case
type Line struct {
Type string `json:"type"`
+2 -2
View File
@@ -1,8 +1,8 @@
// Package waf runs the OWASP Core Rule Set 4.25.0, through Coraza, on the
// method, the URL with its query and the headers of a request, and on its
// body while SWWAF_WAF_BODY_LIMIT is set, with the six changes smallwebwaf
// makes to it, as "Attack detection" under "Settings" in SPEC.md describes
// them. It reads no response.
// makes to it, as "Attack detection" under "Configuration surface" in
// SPEC.md describes them. It reads no response.
//
// smallwebwaf writes only to its state directory, so Coraza is built with
// its no_fs_access tag, as the Dockerfile and script/build build it: of a
+5 -6
View File
@@ -2,12 +2,11 @@
# script/gitea-requests: build the image and run gitea 1.27.3 behind it,
# with every setting of smallwebwaf at its default but SWWAF_UPSTREAM_URL,
# which names gitea's container. Then send through it the gitea requests
# that reading gitea's source found the Core Rule Set refuses, which
# docs/gitea.md records, and a short sample of gitea's ordinary use:
# signing in, pages of files and commits, a diff, the API, a push, clone
# and fetch over HTTP, and two container image pushes. Last, print each
# request smallwebwaf logged, with what it did with it and the ids of the
# Core Rule Set's rules that matched it.
# that reading gitea's source found the Core Rule Set refuses, and a short
# sample of gitea's ordinary use: signing in, pages of files and commits,
# a diff, the API, a push, clone and fetch over HTTP, and two container
# image pushes. Last, print each request smallwebwaf logged, with what it
# did with it and the ids of the Core Rule Set's rules that matched it.
# Every request comes from one client, docker's gateway, so more than
# SWWAF_ERROR_BURST_THRESHOLD, 30, refusals in a minute would ban it, and
# the requests after would show as banned. The containers, the network,