Repository navigation
Darling: let another service send alerts through Darling's channels, routes and mute rules #5654
Copy link
Copy link
Closed
Labels
enhancementNew feature or requestNew feature or request
Description
Claude posting for Erik Darling.
Let a second service raise alerts through Darling. The service records an alert in the store. Darling delivers it through its own channels, routes and mute rules. The second service never holds a webhook URL or any other secret.
Why
- Some checks live outside Darling. Examples are a scheduled script, a job, or a companion service that watches something Darling does not collect.
- Today such a service must post to Slack, Teams or email itself. So it needs its own copy of the webhook URLs. It also skips Darling's routes, mute rules and cooldowns.
- Since Darling: store SQL login passwords on Linux, sealed to the service's key #5387, Darling seals saved webhook URLs and the other secrets to the service's key. Only the service can open them. That is the right model. But it means that another service cannot use the saved URLs.
Design (draft)
- A narrow write. A new
SECURITY DEFINERfunction, for exampleconfig.submit_external_alert(...), records one pending alert. It follows the pattern ofconfig.record_custom_alert_resolution(Custom-alert resolve-on-delete silently skips the recovery row on mcp/viewer paths (config_alert_log grant gap in #3305) #3334):- A fixed
search_path. - A fully parameterized insert, with no dynamic SQL.
REVOKE ALL ... FROM PUBLIC, then a narrowGRANT EXECUTE.
- A fixed
- Registered sources. The operator registers each source by name. A source connects with a login that can execute the function and do nothing else. The function records which source called it.
- A pending table, separate from alert history. The function writes to a new pending table, not to
config_alert_log. So a source can never write a row that claims a delivery. - Darling delivers. The alert pass reads the pending rows. It sends each one through the normal channels, routes, mute rules and cooldowns, the same as its own alerts. Then it writes the usual
config_alert_logrow. It marks the pending row as delivered, muted or failed, with the reason. - Fire and clear. A source can send a fire and a clear for one key (the source, the server name and the metric). So state tracking and resolution notices work the same as for Darling's own alerts.
- Limits. Each source has a rate limit and a maximum payload size. Severity comes from a fixed list. A pending row that is not delivered in time is marked expired, and the self-monitor reports it.
- Visibility. Alert history, the viewer and the MCP tools show the source of each alert. A mute rule can match a source.
Acceptance tests
- A source login can execute the function and nothing else. It cannot read webhook URLs, other secrets or alert history.
- A source cannot insert into
config_alert_logdirectly. - A pending alert is delivered once, also across a service restart.
- A mute rule that matches the alert stops its delivery, and the history row records it as muted.
- Routes and cooldowns apply the same as for Darling's own alerts.
- A fire and then a clear sends the resolution notice.
- A source over its rate limit is refused, with a clear error.
Open questions for Erik
- One login per source, or one shared role with the source name as an argument?
- Delivery delay: read the pending rows in the alert pass, or wake on PostgreSQL
LISTEN/NOTIFY? - Darling only? Lite has no shared store, so this draft leaves Lite out.
Planned for next week.
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
enhancementNew feature or requestNew feature or request
Activity
External alert submit function, source login grants and owner-only ne…
External alert grants: place before the password key revoke, keep the…
External alert function revoke from the three roles moves into the so…
External alert store: claim, mark, expire, reap and firing state, plu…
External alert store: keep the reason trim out of the member-scan gua…
External alerts: family, drain, worker wiring and delivered-if-logged…
External alert drain: live tests for once-only delivery, order, mute,…
External alert drain: write the clear's history row the way Darling's…
External alert drain: master switch passed to the drain and censused;…
External alert drain: the firing state is keyed on the submitted serv…
External alert drain: its own 15-second loop; every pass reaps and re…
External alert drain tests: no clock in the lifecycle class; the drai…
Slack and Teams alerts show alert text as plain text; an external ale…
External alert submit: share-compatible row lock, finite values only,…
23 remaining items
Statement statistics stay readable by pg_read_all_stats after the rev…
The alert sources pg_hba line is written on the start whose role prov…
Test replays of the viewer grants skip every function statement, and …
Align the merged rung pins and the doc comment with the V179 + V180 l…
Source verbs run every owner statement under a pinned search path, se…
Statement statistics grants, pg_hba name quoting and the alert-source…
Alert source add and rotate print a verifying connection string for a…
The rung and mute-rule pins describe the ladder with V180 on top, and…
The external origin is read after the newest sample in the alert cont…
The alert source live tests give each test its own role names and dro…
Darling: other services can raise alerts through Darling's channels, …
erikdarlingdata commentedon Oct 13, 2026
Claude posting for Erik Darling. Done in #5726 (merged to dev as 9f5ac56). The three open questions, as built:
Sources are managed with the add, rotate, list and remove CLI verbs; mute rules can name an external source in the MCP tools and on the web Mute Rules page.
The read caller is sanitized and cut on whole text elements; the web …
Compose rollup self-alert: its failure-record read is counted on the …