WebhookEngine v0.1.6
WebhookEngine v0.1.6
Feature & polish cut covering eight new capabilities (per-resource overrides, IP allowlist, audit log, endpoint test webhook, SignalR endpoint health, validate-time URL guard), three rounds of dashboard polish (a11y, UX, TanStack Query data layer), three reviewer-finding fixes (transient DNS retry, cascade delete, polling debounce), and a backend correctness pass on the IP allowlist matcher, application rate-limiter sweep, and endpoint health tracker. No breaking API changes — the v1 route prefix and Standard Webhooks signature surface are preserved. Test count moved from 211 to 215.
Features / Fixes / Changes
Added
- Endpoint test webhook (F1):
POST /api/v1/dashboard/endpoints/{id}/testfires a customizable, fully-signed webhook to the endpoint URL without enqueueing a realMessage, and returns the receiver's response plus the exact request that was sent. Dashboard endpoint editor carries a Send test drawer. - Per-application rate-limit override (F6):
Application.RateLimitPerSecond1-second sliding-window override complements the per-endpoint per-minute gate; idle-evicted at 15 minutes. - Per-application retention overrides (F3):
Application.RetentionDeliveredDaysandRetentionDeadLetterDaysoverrideWebhookEngine:Retentiondefaults per tenant; the cleanup worker partitions its sweep accordingly. - Per-event-type idempotency window (F4):
EventType.IdempotencyWindowMinutesoverrides the per-app default for tighter or looser dedupe per event family. - Per-endpoint IP allowlist (F8):
Endpoint.AllowedIpsJsoncarries a CIDR positive-list (IPv4 + IPv6); deliveries only proceed when every resolved address sits inside at least one allowed CIDR. - Append-only audit log (F9): Admin actions across applications, endpoints, event types, replay, retry, and rotate-key write a forensic row to the new
audit_logstable with before / after snapshots andrequest_id.GET /api/v1/dashboard/auditexposes a paginated, filterable view. The table holds no FKs — rows survive cascades. - SignalR endpoint health channel (F7):
DeliveryHubbroadcastsEndpointHealthChanged(endpointId, status, circuitState, consecutiveFailures, cooldownUntilUtc)wheneverEndpointHealthTrackermutates an endpoint's circuit or visible status. DashboardEndpointsPageconsumes the event and invalidates its cache. - TanStack Query dashboard data layer (F12): Every dashboard page (Dashboard, Messages, Applications, Endpoints, EventTypes, DeliveryLog) routes server data through
useQuery/useMutation. ManualsetIntervalpolling and the smart-debounce shim are gone in favor of cache-aware refetching driven by SignalR invalidation.EndpointsPageinitial chunk drops from ~1.5 MB to ~20 kB (CodeMirror lazy-loaded).
Changed
- Validator chain rejects private-IP endpoint URLs at create / update (F2). Same SSRF rules already enforced at delivery (
ConnectCallback) now run at validate time too — a misconfigured URL is rejected before the row exists. - Modal a11y, mobile, dvh (DPR-1 + DPR-3):
role="dialog", ARIA wiring, focus trap,max-h-[85dvh], mobile filtermd:grid-cols-3, URL field server-side errors as field-scoped messages, payload editor errors split out, SignalR Live / Offline pill in the EndpointsPage header. - Dashboard consolidation (DPR-2): Shared
StatusBadge,inputClasses, and CodeMirroreditorTheme. CodeMirror isReact.lazy()— the 1.5 MB chunk loads only when the endpoint editor mounts.parseErrorreturns anApiErrorwith optionalfieldErrors. - Backend polish (R2 + R4 + R5):
IpAllowlistMatcher.AllAddressesAllowedshort-circuits empty allowlists before the empty-resolution deny branch (load-bearing ordering).ApplicationRateLimiter._lastSweepTicksisVolatile.Read+ CAS so torn 32-bit reads can't spawn back-to-back sweeps.EndpointHealthTracker.WithEndpointLockAsyncno longer double-fetches the endpoint row. - Dependency refresh: Backend —
Scalar.AspNetCore2.14.10 → 2.14.11,coverlet.collector8.0.1 → 10.0.0. Frontend —react/react-dom/react-is19.2.5 → 19.2.6,react-router7.14.2 → 7.15.0,@codemirror/view6.41.1 → 6.42.1,vite8.0.10 → 8.0.11, plus@tanstack/react-query5.100.9 (drives F12).
Fixed
- Transient DNS failures retry within budget (R1):
SocketException/ArgumentExceptionfrom the IP-allowlist resolution now route throughMarkFailedForRetryAsyncinstead of dead-lettering on first miss; only after the retry budget is exhausted does the message dead-letter. - Application / endpoint deletion cascades to bound messages (R3):
Message → ApplicationandMessage → Endpointforeign keys carryON DELETE CASCADE. Migration20260508081704_CascadeMessageDeleteOnAppAndEndpointis hand-written SQL because EF doesn't diffOnDeletechanges. - Modal focus trap, awaited refetches, SignalR cache invalidation on reconnect (DPR-1): Skeleton loaders carry
aria-busy="true"; mutating actions await their refetch before closing modals;useDeliveryFeed.onreconnectedresetslastHealthChangeso a stale event from before the disconnect doesn't double-fire. - Smart-debounced dashboard polling (R6) folded into F12: SignalR events now invalidate cache keys; TanStack Query handles the refetch cadence.
Security
- Endpoint URL DNS resolution at validator chain (F2): Same private-IP rules already enforced at delivery time now run at create / update — a misconfigured URL is refused before the row exists.
- Per-endpoint IP allowlist (F8): Opt-in CIDR positive-list at delivery time; transient resolver failures retry within the message's normal budget (R1) so flaky DNS doesn't cascade into dead-letter floods.
- Append-only audit log (F9): Forensic trail of admin actions; rows survive cascades for post-incident reconstruction.
Quick Start
docker pull voyvodka/webhook-engine:0.1.6
git clone https://github.com/voyvodka/webhook-engine.git
cd webhook-engine
docker compose -f docker/docker-compose.yml up -dDashboard at http://localhost:5100 — login admin@example.com / changeme (reset before exposing publicly).
Links
- 🐳 Docker Hub:
voyvodka/webhook-engine:0.1.6(multi-arch:linux/amd64+linux/arm64) - 📦 NuGet:
WebhookEngine.Sdk 0.1.6 - 📚 Docs:
docs/— API, DATABASE, ARCHITECTURE, GETTING-STARTED, SELF-HOSTING, RELEASE - 🏠 Landing: webhook.sametozkan.com.tr
- 📋 Full changelog:
CHANGELOG.md— 0.1.6 section