feat(webhook): test ping — admin верифицирует receiver одной кнопкой
После создания subscription / rotate secret admin не имел способа
проверить что receiver жив и валидирует HMAC без ожидания реального
business event. Теперь:
- POST /api/v1/admin/webhooks/subscriptions/{id}/test
- Synchronous: receiver получает synthetic event с теми же headers
что у production delivery (X-Ordinis-Signature, X-Ordinis-Event-Type,
X-Ordinis-Scope) + дополнительный X-Ordinis-Test=true чтобы
receiver мог логировать/филтровать как тест.
- HMAC sign'ится через тот же HmacSigner — admin раскопировал secret
правильно если receiver валидирует. Иначе receiver вернёт 4xx
и UI покажет ошибку.
- SSRF guard validate URL host (private CIDR + allowed-hosts override)
— same policy как у dispatcher.
Bypass'ит outbox/dispatcher — нет webhook_deliveries row, нет attempt
count, нет следов в аудите доставок (это test, не business event).
UI:
- Кнопка 'Тест ping' с PaperPlaneTilt иконкой рядом с 'Сменить secret'
на webhook detail page.
- Inline Alert после ответа: success/failure/rejected с HTTP status,
latency, body preview / error message. Dismiss '✕'.
RBAC: RESTRICTED — endpoint отправляет HTTP request на user-controlled
URL (potential abuse vector если бы был INTERNAL).
Tests: rest-api compiles, 76 admin-ui passed.
This commit is contained in:
@@ -34,6 +34,11 @@ i18n
|
||||
'webhooks.action.create': 'Создать',
|
||||
'webhooks.action.delete': 'Удалить',
|
||||
'webhooks.action.rotateSecret': 'Сменить secret',
|
||||
'webhooks.action.test': 'Тест ping',
|
||||
'webhooks.test.success': 'Receiver получил test event и ответил 2xx',
|
||||
'webhooks.test.failure': 'Receiver не принял test event',
|
||||
'webhooks.test.rejected': 'Запрос не отправлен (SSRF guard / serialization)',
|
||||
'webhooks.test.latency': 'latency',
|
||||
'webhooks.confirmDelete': 'Удалить подписку «{{name}}»? Все pending deliveries удалятся каскадом.',
|
||||
'webhooks.confirmRotate': 'Сменить HMAC secret? Старый сразу перестанет работать — receiver надо обновить заранее.',
|
||||
'webhooks.field.name': 'Имя подписки',
|
||||
@@ -285,6 +290,11 @@ i18n
|
||||
'webhooks.action.create': 'Create',
|
||||
'webhooks.action.delete': 'Delete',
|
||||
'webhooks.action.rotateSecret': 'Rotate secret',
|
||||
'webhooks.action.test': 'Test ping',
|
||||
'webhooks.test.success': 'Receiver got the test event and replied 2xx',
|
||||
'webhooks.test.failure': 'Receiver rejected the test event',
|
||||
'webhooks.test.rejected': 'Request not sent (SSRF guard / serialization)',
|
||||
'webhooks.test.latency': 'latency',
|
||||
'webhooks.confirmDelete': 'Delete subscription "{{name}}"? All pending deliveries will be cascade-deleted.',
|
||||
'webhooks.confirmRotate': 'Rotate HMAC secret? The old one stops working immediately — update the receiver first.',
|
||||
'webhooks.field.name': 'Subscription name',
|
||||
|
||||
Reference in New Issue
Block a user