From ddcb0dca07d8157745337044949f50cc3bc8eb00 Mon Sep 17 00:00:00 2001 From: sneak Date: Fri, 2 Oct 2026 06:09:21 +0000 Subject: [PATCH] watcher: startup notification no longer says every endpoint works (closes #230) The startup notification ended "All notification channels are working.", but it is written once and handed to every notification endpoint before any delivery has succeeded or failed, so the claim was never checked and was false whenever one endpoint refused it. It now says only that it is a test sent to every configured notification endpoint. The startup notification test checks the whole message. Model: opus-5-5 --- TODO.md | 2 ++ internal/watcher/watcher.go | 8 +++++--- internal/watcher/watcher_test.go | 13 +++++++++++-- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/TODO.md b/TODO.md index baedf40..2910b41 100644 --- a/TODO.md +++ b/TODO.md @@ -19,6 +19,8 @@ trial run of the finished image: https://git.eeqj.de/sneak/dnswatcher/issues/149 # Completed Steps +- 2026-10-02: the startup notification no longer says every notification + endpoint works; it says it is a test sent to each of them (closes #230). - 2026-10-02: a Mattermost webhook that answers an HTTP error is logged as `mattermost notification failed`, not as a Slack failure (closes #227). - 2026-10-02: durations in the log are written as text such as `2m0s`, not as a diff --git a/internal/watcher/watcher.go b/internal/watcher/watcher.go index 4e006cc..50fe163 100644 --- a/internal/watcher/watcher.go +++ b/internal/watcher/watcher.go @@ -1154,8 +1154,9 @@ func (w *Watcher) saveState() { // maybeSendTestNotification sends a startup status notification // after the first full scan completes, if SEND_TEST_NOTIFICATION -// is enabled. The message is clearly informational ("all ok") -// and not an error or anomaly alert. +// is enabled. The message is informational, not an error or anomaly +// alert. It is written before it reaches any endpoint, so it claims +// nothing about whether the endpoints work. func (w *Watcher) maybeSendTestNotification(ctx context.Context) { if !w.config.SendTestNotification { return @@ -1167,7 +1168,8 @@ func (w *Watcher) maybeSendTestNotification(ctx context.Context) { "dnswatcher has started and completed its initial scan.\n"+ "Monitoring %d domain(s) and %d hostname(s).\n"+ "Tracking %d port endpoint(s) and %d TLS certificate(s).\n"+ - "All notification channels are working.", + "This is a test notification, sent to every configured "+ + "notification endpoint.", len(snap.Domains), len(snap.Hostnames), len(snap.Ports), diff --git a/internal/watcher/watcher_test.go b/internal/watcher/watcher_test.go index 45bfd93..46b40cc 100644 --- a/internal/watcher/watcher_test.go +++ b/internal/watcher/watcher_test.go @@ -875,18 +875,27 @@ func TestSendTestNotification_ViaRun(t *testing.T) { notifications := deps.notifier.getNotifications() + // No names are configured, so every count is 0. + wantMessage := "dnswatcher has started and completed its initial scan.\n" + + "Monitoring 0 domain(s) and 0 hostname(s).\n" + + "Tracking 0 port endpoint(s) and 0 TLS certificate(s).\n" + + "This is a test notification, sent to every configured " + + "notification endpoint." + found := false for _, n := range notifications { if n.Priority == "success" && - n.Title == "✅ dnswatcher startup complete" { + n.Title == "✅ dnswatcher startup complete" && + n.Message == wantMessage { found = true } } if !found { t.Errorf( - "expected startup test notification, got: %v", + "expected startup test notification with message %q, got: %v", + wantMessage, notifications, ) }