Webhooks¶
Webhook — це HTTP POST від BCP Portal на ваш endpoint при настанні певної події. Альтернатива polling-у API.
Навіщо¶
- Real-time доставка findings у ваш SIEM / ticketing / Slack.
- Автоматизація reaction (наприклад, при critical finding одразу створити Jira-тікет).
- Інтеграція з внутрішніми системами без потреби polling.
Налаштування¶
- Settings → Integrations → Webhooks → New.
- Ввести:
- URL — куди надсилати POST.
- Events — які події підписатись (див. нижче).
- Secret — для HMAC-підпису. Генерується автоматично, можна змінити.
- Active — вкл/викл.
- Save → платформа відразу надішле тестовий ping для перевірки.
Типи подій¶
| Подія | Коли тригериться |
|---|---|
finding.created |
Нова знахідка |
finding.updated |
Зміна статусу або деталей |
finding.resolved |
Закрита як resolved або false_positive |
scan.completed |
Завершився сканування |
scan.failed |
Помилка скану |
report.generated |
Згенеровано звіт |
member.added |
Додано користувача в організацію |
member.removed |
Видалено користувача |
Можна підписатись на конкретні події або на всі.
Payload¶
Загальний формат:
json
{
"event": "finding.created",
"timestamp": "2026-06-29T10:23:45Z",
"organization_id": "org_abc123",
"data": {
// event-specific payload
}
}
Приклад: finding.created¶
json
{
"event": "finding.created",
"timestamp": "2026-06-29T10:23:45Z",
"organization_id": "org_abc123",
"data": {
"id": "find_xyz789",
"severity": "critical",
"source": "github",
"title": "AWS Access Key in public repo",
"description": "Found AWS Access Key (AKIA...) in commit abc123 of repo example/test",
"data_source": "yourcompany.com",
"discovered_at": "2026-06-29T10:23:40Z",
"status": "new",
"url": "https://bcp.bytecode.team/findings/find_xyz789",
"external_url": "https://github.com/example/test/blob/abc123/file.env#L42",
"tags": ["aws", "production"]
}
}
Верифікація підпису¶
Кожен webhook містить заголовок X-BCP-Signature з HMAC-SHA256 підпису payload.
Python¶
```python import hmac import hashlib
def verify_signature(payload_body: bytes, signature_header: str, secret: str) -> bool: expected = hmac.new( secret.encode(), payload_body, hashlib.sha256 ).hexdigest() return hmac.compare_digest(f"sha256={expected}", signature_header) ```
Node.js¶
```javascript const crypto = require('crypto');
function verifySignature(payloadBody, signatureHeader, secret) {
const expected = crypto
.createHmac('sha256', secret)
.update(payloadBody)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(sha256=${expected}),
Buffer.from(signatureHeader)
);
}
```
⚠️ Використовуйте constant-time comparison (hmac.compare_digest / crypto.timingSafeEqual), не звичайний == — це захищає від timing-attacks.
Retry policy¶
Якщо ваш endpoint повертає не 2xx:
- 3 спроби з expontntial backoff: 1s, 10s, 60s.
- Після 3 невдалих — webhook позначається як failed, скидається у Delivery log.
- Якщо 10 поспіль доставок failed — webhook автоматично deactivate, надсилається email власнику.
Delivery log¶
Settings → Integrations → Webhooks → {your webhook} → Delivery log — історія усіх доставок з:
- Status (delivered / failed / retrying).
- HTTP code відповіді.
- Latency.
- Payload (можна повторно надіслати).
Зберігається 30 днів.
Best practices¶
- Respond fast — поверніть 200 одразу, обробляйте payload асинхронно. Якщо ваш endpoint займає > 10 секунд, ми порахуємо timeout.
- Idempotency — той самий webhook може прийти повторно при retry. Перевіряйте
data.idіeventщоб не дублювати дії. - Verify signature — інакше зловмисник може підробити webhook і обманути ваші системи.
- Logging — пишіть свої логи для troubleshooting.
Тестування локально¶
Можна використати ngrok або подібний tunnel для тестування на локальному endpoint.
Альтернативно — webhook.site як швидкий debug-receiver.