Rate-limit the public webhook receiver endpoint (closes #64)
All checks were successful
check / check (push) Successful in 2m37s
All checks were successful
check / check (push) Successful in 2m37s
The public receiver /webhook/{uuid} had no rate limiting: anyone
who learns an entrypoint UUID can flood it, inflating the
per-webhook database and the delivery queue.
Add a dedicated limit scoped to the receiver route, keyed per
client IP per request path (the path contains the entrypoint
UUID), so one misbehaving sender is throttled without affecting
other senders of the same entrypoint or other entrypoints.
Requests over the limit get a 429; httprate adds the Retry-After
header per RFC 6585. IP extraction honours X-Forwarded-For,
X-Real-IP, and True-Client-IP for reverse-proxy deployments.
The limit is RECEIVER_RATE_LIMIT requests per minute, default
120. A set-but-unparseable or non-positive value aborts startup
via the new envPositiveInt strict parser rather than silently
falling back to the default. envInt's other callers are
unchanged; converting them is tracked in #80.
Also update the README env table and Rate Limiting design
section, and sync TODO.md.
This commit is contained in:
31
TODO.md
31
TODO.md
@@ -10,24 +10,27 @@
|
||||
|
||||
# Status
|
||||
|
||||
pre-1.0. No git tags exist. main (afe88c6) is a working webhook proxy
|
||||
pre-1.0. No git tags exist. main (81413c5) is a working webhook proxy
|
||||
with auth, CSRF/SSRF protections, login rate limiting, Slack target,
|
||||
policy compliance (#6), and pinned lint tooling (#55). Note: TODO.md was
|
||||
deliberately deleted from this repo in f9a9569 (2026-03-01, #6); its
|
||||
content was folded into the README TODO section, which this draft
|
||||
reconstructs as of 2026-07-06.
|
||||
policy compliance (#6), pinned lint tooling (#55), a per-webhook event
|
||||
retention reaper (#63), and delivery targets behind a Target interface
|
||||
(#77). Work is tracked as Gitea issues (the authoritative TODO); this
|
||||
file is a summary. Note: TODO.md was deliberately deleted from this
|
||||
repo in f9a9569 (2026-03-01, #6); its content was folded into the
|
||||
README TODO section, which this draft reconstructs as of 2026-07-06.
|
||||
|
||||
# Next Step
|
||||
|
||||
Implement automatic event retention cleanup based on retention_days: a
|
||||
periodic maintenance job that deletes Events, Deliveries, and
|
||||
DeliveryResults older than the parent webhook's retention_days from each
|
||||
per-webhook event database. The field exists on the Webhook model and
|
||||
the README promises the behavior, but nothing enforces it, so event
|
||||
databases currently grow without bound.
|
||||
Manual event redelivery from the web UI (replay is a core promised
|
||||
capability in the README rationale).
|
||||
|
||||
# Completed Steps
|
||||
|
||||
- 2026-08-07 Rate-limit the public webhook receiver per client IP per
|
||||
entrypoint, env-configurable with fail-loud parsing (#64)
|
||||
- 2026-08-07 Per-webhook event retention reaper (#63); NoCache
|
||||
middleware for authenticated pages (#61); Target interface refactor
|
||||
(#77)
|
||||
- 2026-07-07 Adopted scripts-to-rule-them-all: `script/` entrypoints,
|
||||
Makefile shims, README Entrypoints section
|
||||
- 2026-03-25 pin golangci-lint Docker image for linting (#55)
|
||||
@@ -51,12 +54,10 @@ databases currently grow without bound.
|
||||
|
||||
# Future Steps
|
||||
|
||||
- Manual event redelivery from the web UI (replay is a core promised
|
||||
capability in the README rationale)
|
||||
- Delivery status and retry management UI
|
||||
- Per-webhook rate limiting in the receiver handler (per-webhook config
|
||||
plus handler enforcement; global limits must not apply to receiver
|
||||
endpoints)
|
||||
plus handler enforcement, layered on the env-level receiver limit
|
||||
from #64; global limits must not apply to receiver endpoints)
|
||||
- Webhook signature verification for GitHub and Stripe HMAC formats
|
||||
- API key authentication for programmatic access (APIKey model exists;
|
||||
Bearer token middleware does not)
|
||||
|
||||
Reference in New Issue
Block a user