You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Phase 2 of #256: DB-backed, operator-managed webhook subscriptions delivered
through the same bus as the phase-1 config webhook. Multiple endpoints, runtime
management via REST (no restart), per-endpoint event filter, signing secret, and
delivery-status observability.
- store: webhook_subscriptions table (migration 021) + CRUD + RecordDelivery.
The HMAC secret is envelope-encrypted under the master key (per-row DEK wrapped
under the master, secret sealed under the DEK — the cas table's scheme), so it
never leaves the server in cleartext and is never returned by the API.
- webhook.Dispatcher refactored from a single static target to fan-out: it
delivers each event to the optional static config target plus all matching
managed subscriptions from a SubscriptionSource, with per-target retry and
status recording. StoreSource resolves active subscriptions and decrypts their
secrets at delivery time. Phase-1 config behavior is preserved.
- api: owner-scoped REST CRUD at /api/v1/webhook-subscriptions (admin sees all,
operators see their own). The secret is write-only (omit to keep, "" to clear,
value to set); responses expose only has_secret. config.ValidateWebhookURL is
exported and reused for URL/SSRF validation.
- serve.go: the dispatcher now always runs (managed subs are created at runtime)
with a store-backed source; cert.expiring still folds into the bus.
- api/openapi.yaml: the CRUD endpoints + schemas; contract tests validate the
responses. docs/webhooks.md documents managed subscriptions.
The route-scoping registry and the cross-operator leak test are extended to
cover the new collection and single-resource routes.
Web UI for subscriptions remains a follow-up (still tracked in #256).
Refs #256
0 commit comments