feat: generic webhook as fourth reminder channel (#950) #960

Closed
sleepy wants to merge 2 commits from fix/950-webhook-reminder into dev
Owner

Add generic webhook as a reminder channel (alongside browser notification, email, ntfy).

  • Webhook URL + optional auth header in settings
  • SSRF-guarded POST on reminder fire (validate_webhook_url)
  • Graceful failure handling (log, do not block)
  • Frontend: webhook channel option + URL/auth header inputs
  • Fixed pre-existing bugs: untracked webhook_manager.fire calls → fire_and_forget
  • settings_scrub: mask _auth_header for non-admin users
  • 3 tests passing

Closes #950

Add generic webhook as a reminder channel (alongside browser notification, email, ntfy). - Webhook URL + optional auth header in settings - SSRF-guarded POST on reminder fire (validate_webhook_url) - Graceful failure handling (log, do not block) - Frontend: webhook channel option + URL/auth header inputs - Fixed pre-existing bugs: untracked webhook_manager.fire calls → fire_and_forget - settings_scrub: mask _auth_header for non-admin users - 3 tests passing Closes #950
- Add reminder_webhook_url and reminder_webhook_auth_header to settings
- Fire POST with JSON payload to configured webhook URL on reminder
- SSRF-guarded via validate_webhook_url (DNS resolution, private IP blocking)
- Failures logged and handled gracefully (do not block reminder dispatch)
- Frontend settings UI: Webhook option in channel selector with URL + auth header fields
- Webhook auth header masked in non-admin settings responses (_auth_header scrub pattern)
- Fix untracked webhook fire calls (asyncio.create_task -> fire_and_forget) in
  chat_types.py, chat_helpers.py, webhook_routes.py
- Add _spawn_tracked task management to WebhookManager (prevents GC mid-flight)
- Port improved sanitize_error with _redact_ip_candidate (proper IPv6 handling, ReDoS-safe)
- Port test_webhook_emitters_use_manager.py (AST scan for untracked fire calls)
- Payload structure verification (event, note_id, title, body, synthesis)
- Auth header inclusion when configured, exclusion when empty
- Empty URL error handling (webhook_error set)
- Non-2xx response handling (webhook_sent=False, error populated)
- SSRF guard tests (127.0.0.1, localhost, 192.168.x.x blocked)
- Synthesis field present in payload (None when LLM synthesis off)
- Content-Type and User-Agent header verification
- Uses autouse fixture to clear dedup cache between tests
- Evicts conftest database stubs so real src.webhook_manager imports
sleepy closed this pull request 2026-06-18 19:34:13 +02:00

Pull request closed

Sign in to join this conversation.
No description provided.