feat: add Apprise as a fourth notification channel (#1644)

* feat: add Apprise as a fourth notification channel

Support keyed and stateless Apprise endpoints with secret-safe public DTOs, fail-closed malformed config, and mode-specific Settings UI. Docs and screenshots updated for four-channel Channels and routing.

* fix: harden Apprise secrets at rest and preserve-on-write saves

Encrypt Apprise endpoint and config with CryptoService so a downgrade cannot leak via SELECT *. Align channel and routing saves so blank destination fields omit config on same-mode URL edits, enforce keyed notify IDs, and keep secrets_redacted truthful.

* fix: harden Apprise route type changes and mixed-version config UI

Require a raw channel_url when switching notification-route types so ciphertext cannot strand under Discord/Slack/webhook. Default missing remote apprise status, replace Channels state on node switch, and exercise the production config-column migrator.

* fix: tolerate stub fleet configuration payloads without agents

Normalize remote Apprise agent status only when notifications.agents is present so successful Pilot/stub fetches stay online instead of throwing into the offline catch path.

* fix: correct TypeScript in configuration normalize tests

* fix: ignore stale Channels agent bodies after node switch

Compare the active node after response JSON parsing so a slow body
cannot overwrite the newly selected node's channel state.

* fix: isolate corrupt Apprise crypto and keep keyed Tags visible

Decrypt failures on one Apprise row no longer 500 agent/route lists or
suppress sibling channel dispatch. Treat public /notify/<redacted> as keyed
so Tags remain editable after reload.
This commit is contained in:
Anso
2026-07-18 16:32:58 -04:00
committed by GitHub
parent 674220b9de
commit 83b3d932e5
42 changed files with 2916 additions and 136 deletions
+4 -3
View File
@@ -378,7 +378,7 @@ Quick reference:
**Scope:** Per-node (each node has its own notification agents; remote nodes dispatch alerts through their own channels)
Configure external destinations for alert notifications. Three agent types are available on separate tabs: **Discord**, **Slack**, and **Webhook**. The masthead publishes a **CHANNELS** pill showing how many agents are enabled (for example, `2/3`).
Configure external destinations for alert notifications. Four agent types are available on separate tabs: **Discord**, **Slack**, **Webhook**, and **Apprise**. The masthead publishes a **CHANNELS** pill showing how many agents are enabled (for example, `2/4`).
For each agent:
@@ -386,6 +386,7 @@ For each agent:
|-------|-------------|
| **Enabled** toggle | Activates or deactivates this agent. Disabled agents receive no messages even if a URL is saved. |
| **Webhook URL** | The endpoint Sencho will POST to when an alert fires. |
| **Apprise** | Use a keyed `/notify/<key>` endpoint with optional tags, or a stateless `/notify` endpoint with destination URLs. Apprise accepts HTTP or HTTPS. |
Click **Save** to persist changes. Click **Test** to send a test payload immediately and verify delivery.
@@ -410,9 +411,9 @@ Create routing rules that direct specific alert types to specific notification c
| **Stack patterns** | Glob patterns to match stack names (multi-select). |
| **Labels** | Apply this rule to stacks that carry any of the selected labels. |
| **Categories** | Event categories that trigger the rule (crash, deploy, vulnerability, etc.). |
| **Channel type** | `discord`, `slack`, or `webhook`. |
| **Channel type** | `discord`, `slack`, `webhook`, or `apprise`. |
| **Channel URL** | The destination endpoint for this rule. |
| **Priority** | Order in which rules are evaluated; the first match wins. |
| **Priority** | Sort order among matching rules. Every matching route fires; priority does not stop later matches. |
| **Enabled** toggle | Mute a rule without deleting it. |
Each rule keeps an execution history (collapsible per row) showing which alerts triggered it, when, and whether the delivery succeeded.