Files
webhooker/TODO.md
sneak 67ce7978c4
All checks were successful
check / check (push) Successful in 8s
Update TODO.md for the completed 1.0.0 milestone
Records the trusted-proxy gating (#88), the hop cap (#124) and the
bounded scan (#133), and corrects the Workflow section, which still
described branching from main and committing TODO.md alongside the
work — both contradicted by the branch-per-issue-onto-next model and
by the decision on #112 that issue branches leave this file alone.
2026-08-12 10:20:20 +00:00

7.0 KiB

Workflow

One issue per unit of work, one branch and one PR per issue:

  • ensure a tracked issue exists with a definition of done
  • branch from next (never from main)
  • do the work; open a PR based on next (never on main)
  • pass an independent review, then the manager squash-merges into next
  • push; nothing stays local-only

next is the branch for the next milestone and must stay green and mergeable to main without notice. One next -> main PR accumulates the milestone; releases are cut from main separately.

Issue branches do NOT touch this file — the manager maintains it on next. Every branch editing TODO.md conflicts with every other (#112).

Status

pre-1.0. No git tags exist. main (4f5ecb1) is a working webhook proxy with auth, CSRF/SSRF protections, login rate limiting, Slack target, event retention (#63), the database archiving target (#43), the admin password change flow (#65), policy compliance (#6), pinned lint tooling (#55), and fail-loud configuration parsing (#80).

next (9bfd033) holds the completed 1.0.0 milestone: every issue in it is closed, and it is verified green by cache-defeated container runs rather than by the CI badge, which can pass without executing anything (#119). 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

Tag 1.0.0 from main once the milestone PR merges, then repair the CI gate (#119) before the next cycle's work lands — a gate that can report success without running is the one thing every other guarantee here rests on.

Completed Steps

  • 2026-08-12 Bound the X-Forwarded-For scan's allocation to the hop cap: the reverse walk cuts entries with strings.LastIndexByte instead of joining and splitting, so a 1 MB header allocates 16 bytes rather than 1.6 MB per request on the unauthenticated receiver. Semantics proven unchanged by differential testing against the previous implementation (#133)
  • 2026-08-12 Cap the X-Forwarded-For hop walk at 64 entries, so an attacker-supplied chain cannot burn unbounded CPU in the rate-limit key function; running off the end falls back to the peer address (#124)
  • 2026-08-12 Gate forwarded-header trust behind a TRUSTED_PROXIES CIDR list: all three rate limiters key on the connection's own address unless the direct peer is a configured proxy, in which case X-Forwarded-For is walked right to left for the first non-proxy hop. Default trusts nothing, and a set-but-unparseable value aborts startup. Before this, any client could mint a fresh bucket or drain another's by rotating a spoofed header (#88)
  • 2026-08-11 Web UI cleanup: nav terminology unified on Webhooks, the Profile settings placeholder removed, a progressive-enhancement copy button for the entrypoint URL, and retention form copy that states the actual policy (deletion by the reaper, 0 retains forever) (#57)
  • 2026-08-09 Inactivity-based session timeout: sliding idle expiry (SESSION_IDLE_TIMEOUT, default 24h) refreshed on authenticated requests, with the 7-day absolute cap kept as an independent backstop that activity never extends (#66)
  • 2026-08-09 Restart recovery and the 60s retry sweep terminally fail an orphaned retrying delivery whose target type no longer supports retries, recording a DeliveryResult with the reason instead of leaving the delivery stuck forever (#82)
  • 2026-08-09 Root the delivery engine's worker pool and the retention reaper's sweep loop at context.Background() rather than the fx OnStart hook context (#97), which carries fx's 15s start timeout and killed both roughly fifteen seconds after boot: the proxy silently stopped delivering webhooks entirely, and the reaper never ran a single sweep under its default one-hour interval
  • 2026-08-09 Archive writer lifecycle (#89): deleting a webhook (or its last database target) evicts the cached archive writer and closes its handle while deliberately leaving archive-{webhookID}.db on disk, and a new ArchiveSweeper prunes idle archives on the existing RETENTION_SWEEP_INTERVAL without ever creating an archive file
  • 2026-08-09 Configuration parsing fails loudly on set-but-unparseable environment values: envInt removed in favour of envPositiveInt plus a PORT range check, envBool now parses with strconv.ParseBool, and defaults apply only to unset variables (#80)
  • 2026-08-07 Automatic event retention cleanup based on retention_days, deleting expired events, deliveries, and delivery results from each per-webhook event database (#63)
  • 2026-08-07 Update golangci-lint to v2.12.2 (Docker image digest in Dockerfile, release-archive sha256 pins in script/bootstrap), adopt the canonical .golangci.yml (v2 linters.settings layout so lll/funlen/cyclop/dupl thresholds actually apply), and fix all newly surfaced lint findings
  • 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)
  • 2026-03-18 CSRF middleware detects TLS per-request, fixing login over plain HTTP and behind reverse proxies (#54)
  • 2026-03-17 root path redirects based on auth state (#52)
  • 2026-03-17 CSRF protection, SSRF prevention for HTTP delivery targets with DNS rebinding defense, and per-IP login rate limiting (#42)
  • 2026-03-17 Slack target type for incoming webhook notifications (#47)
  • 2026-03-17 Dockerfile absolute paths and static linking (#49); absolute dev DATA_DIR default and clarified env docs (#46)
  • 2026-03-05 security headers middleware, session regeneration on login, request body size limits (#41)
  • 2026-03-04 tests for delivery, middleware, and session packages (#32); removed globals.Buildarch (#31)
  • 2026-03-04 1.0 MVP merge: Webhook/Entrypoint/Target rename, core delivery engine with bounded worker pool and circuit breaker, parallel fan-out, per-webhook event databases, management UI (#16)
  • 2026-03-01 repo brought to REPO_POLICIES standards; TODO.md folded into README (#6)

Future Steps

  • 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)
  • Webhook signature verification for GitHub and Stripe HMAC formats
  • API key authentication for programmatic access (APIKey model exists; Bearer token middleware does not)
  • REST API v1
    • CRUD for webhooks, entrypoints, targets
    • event viewing and filtering endpoints
    • event redelivery endpoint
    • OpenAPI specification
  • Analytics dashboard: success rates, response times, volume
  • A remember-me option at login
  • Password change and reset flow
  • Later, nice to have
    • email delivery target type
    • SNS and S3 delivery targets
    • data transformations (e.g. webhook to Slack message formatting)
    • JSONL file delivery with periodic S3 upload
    • webhook event search and filtering
    • multi-user with role-based access control