Skip to content

WebhookEngine v0.1.5

Choose a tag to compare

@voyvodka voyvodka released this 05 May 21:01
· 91 commits to main since this release
bac5d13

WebhookEngine v0.1.5

Post-audit hardening release. A multi-agent deep audit covered security, memory, concurrency, code quality, frontend, operations, timezone correctness, and NuGet SDK compliance; the resulting fixes (F1–F10) plus an idempotency race fix (F7) and an SDK target-framework simplification all land here. No breaking API changes — the v1 route prefix and Standard Webhooks header names are preserved.

Features / Fixes / Changes

Added

  • health probes: /health/live (process up) and /health/ready (AppReadinessGate + DbContext.CanConnectAsync) for orchestrators (F5)
  • observability: OpenTelemetry tracing with optional OTLP export via OpenTelemetry:OtlpEndpoint (F5)
  • sdk: WebhookVerifier for Standard Webhooks signature verification — FixedTimeEquals, 5-min default tolerance, whsec_ / base64 secrets, multi-value signatures (F9)

Changed

  • sdk: target framework simplified from net10.0;net9.0;net8.0 to net10.0 only — pre-v1.0 cleanup, NuGet badge flips to .NET 10.0
  • memory: IMemoryCache size-bounded (SizeLimit = 10_000) with per-app cancellation-token-source invalidation (F4)
  • shutdown: HostOptions.ShutdownTimeout = 45s so in-flight HTTP deliveries can drain on SIGTERM (F10)
  • security: dashboard admin default credentials rejected at startup outside Development (F5)

Fixed

  • idempotency race: UNIQUE partial index on (app_id, endpoint_id, idempotency_key) + Stripe-style 23505-replay + retention NULL-out for window reuse (F7)
  • duplicate attempts on lock loss: CAS guards on Mark{Delivered,FailedForRetry,DeadLetter}Async returning bool (F2)
  • circuit-breaker race: EndpointHealthTracker mutations serialized via pg_advisory_xact_lock namespace 100_001 (F3)
  • frontend: webhookengine:auth-expired CustomEvent on 401 + RouteErrorBoundary for ChunkLoadError after deploys (F8)
  • memory leaks: HttpResponseMessage disposal + EndpointRateLimiter idle-window eviction (15-min IdleAfter, 5-min sweep) (F9)
  • migration race: startup migration block wrapped in pg_advisory_lock namespace 200_000 (F5)

Security

  • SSRF + DNS rebinding: PrivateIpDetector blocks RFC1918/loopback/link-local/CGNAT/IPv6 unique-local; SocketsHttpHandler.ConnectCallback pins resolved IP (F1)
  • headers + metrics gate: HSTS / CSP / X-Frame-Options DENY / X-Content-Type-Options / Referrer-Policy / Permissions-Policy; /metrics Bearer-token auth via WebhookEngine:Metrics:ScrapeToken; cookie SecurePolicy = Always outside Dev/Testing (F6)
  • custom headers: CustomHeaderPolicy rejects reserved headers (Authorization, Cookie, Host, Content-*, webhook-*), strips CR/LF, bounds size (F10)

Migration

One auto-applying migration ships in this release: 20260505140607_AddIdempotencyUniqueIndex. It NULL-outs any pre-existing duplicate (app_id, endpoint_id, idempotency_key) triples (keeping the most-recent row per group) before creating the unique index, so it cannot fail on legacy data.

Quick Start

docker pull voyvodka/webhook-engine:0.1.5
docker compose up

Links