Commit Graph
4 Commits
Author SHA1 Message Date
clawbot 6ec52e5b87 Take in an admin's edits of the state files while running (closes #68)
check / check (push) Waiting to run
smallwebwaf watches SWWAF_STATE_DIR with fsnotify and takes in a saved
edit of a state file in place of what it held. It knows its own writes
by the SHA-256 of what it last read or wrote; each write first takes in
an edit made since. An edit that does not parse is renamed to
<name>.bad at the next write. Each edit taken in or set aside is logged
and counted. Every ban on a netblock is checked, and the next ban is
worked out from the one that ended last. README.md says how to add and
lift a ban.

Judgement call: a broken edit is set aside at the next write, since an
editor's file can be read half written.

Model: opus-5-5
2026-10-06 14:18:13 +02:00
clawbot 234c5eac60 Serve Prometheus metrics behind SWWAF_METRICS_TOKEN (closes #23)
check / check (push) Waiting to run
GET /_smallwebwaf/metrics answers in the Prometheus text format for a
request carrying SWWAF_METRICS_TOKEN, 401 without it and 404 while it is
unset. Every request under /_smallwebwaf/ but the health check now goes
through the checks and is answered where it would be forwarded, 404 for
any path but the metrics, so none reaches the app. In the client's
history a 401 counts as refused, the metrics and the 404s as neither.
SWWAF_METRICS_TOP_N bounds the series by country, the rest counted as
other.

Deviation: go.mod and go.sum written by hand, as go runs only through
make.
Deviation: no metrics yet for state files read again after an edit or
edits set aside; that work is not merged.

Model: opus-5-5
2026-10-06 11:40:27 +02:00
clawbot f51459fbfe Per-client request rate limits over a minute, an hour and a day (closes #43)
check / check (push) Successful in 2m50s
Each client, one IPv4 address or one IPv6 /64, is counted in two buckets
per window, the earlier weighted by how much of it the window covers; at
most 20,000 clients are kept, least recently seen dropped first. A
request over SWWAF_RATE_LIMIT_PER_MINUTE, _HOUR or _DAY (1000, 10000,
50000, or off) gets 429 before reaching the app. Refused requests count,
413s included. A clock set back over a second behind a bucket's start
restarts that window. The log line gains limit_hit and the action
rate_limited.

Deviation from SPEC.md, per the issue: the 20,000 bound and /64 are fixed.
Judgement call: golang-lru/v2 holds the table; httprate does not count refused requests.
Deviation: go.mod and go.sum hand-written; no make target tidies them.

Model: opus-5-5
2026-10-04 04:24:34 +02:00
clawbot d76715b0df Pass-through proxy with timeouts, size limits and a request log (closes #13)
check / check (push) Successful in 1m29s
Milestone 1, the repo's first code. smallwebwaf passes each request to the app and the answer back unchanged, streaming bodies and WebSocket upgrades, within four timeouts (client and app, request and response) and two size limits, and writes one JSON line per request to stdout. Every setting has an SWWAF_ name and a default, and an invalid value stops the start. The repo gets the standard layout: script/ entrypoints, make targets that call them, a Dockerfile that runs the checks, and the Gitea workflow.

Disclosure: SPEC.md changed. Go's server reads the request line and headers before smallwebwaf sees the request, so slow headers are closed without an answer, and neither slow nor oversized headers get a log line.
Disclosure: standard library only.

Model: opus-5-5
2026-10-03 17:24:34 +02:00