Compare commits

..
1 Commits
Author SHA1 Message Date
sneak 8818e42ecc notify: the log names a notification endpoint, not its webhook URL (closes #288)
check / check (push) Canceled after 0s
With debug logging on, each delivery logged the full Slack, Mattermost
or ntfy URL, whose path or query lets anyone who has it post to the
channel or topic. The two debug lines now give the endpoint's name and
the title; sendSlack is told which of Slack or Mattermost it sends to.
A webhook URL that does not parse gave a startup error quoting the
whole URL; it now gives only the reason. Errors from a failed request
come from the transport, not from an HTTP client, and carry no part of
the path or query; a test now checks that too.

Model: opus-5-5
2026-10-15 12:19:20 +00:00
+22 -9
View File
@@ -1129,6 +1129,7 @@ type logRecord struct {
Msg string `json:"msg"`
Endpoint string `json:"endpoint"`
Title string `json:"title"`
Error string `json:"error"`
}
// parseLog decodes each line of a JSON log.
@@ -1225,7 +1226,8 @@ func TestSendNotificationDebugLogOmitsWebhookURL(t *testing.T) {
// TestSendNotificationErrorLogOmitsWebhookURL checks that a delivery
// to each endpoint that cannot connect logs the transport's error,
// on every attempt and at the end, without any part of the URL's
// which names the refused connection, on its retry line and on its
// final failure line, and that no line holds any part of the URL's
// path or query.
func TestSendNotificationErrorLogOmitsWebhookURL(t *testing.T) {
t.Parallel()
@@ -1239,20 +1241,31 @@ func TestSendNotificationErrorLogOmitsWebhookURL(t *testing.T) {
assertNoWebhookSecret(t, logs)
var failed []string
// For each endpoint, the messages of its lines whose error names
// the refused connection, in the order they were logged.
got := map[string][]string{}
for _, record := range parseLog(t, logs) {
if record.Msg == "failed to send notification after retries" {
failed = append(failed, record.Endpoint)
if strings.Contains(record.Error, "connection refused") {
got[record.Endpoint] = append(
got[record.Endpoint], record.Msg,
)
}
}
slices.Sort(failed)
lines := []string{
"notification delivery failed, retrying",
"failed to send notification after retries",
}
want := map[string][]string{
endpointNtfy: lines,
endpointSlack: lines,
endpointMattermost: lines,
}
want := []string{endpointMattermost, endpointNtfy, endpointSlack}
if !slices.Equal(failed, want) {
t.Errorf("endpoints that logged a failure = %v, want %v",
failed, want)
if !maps.EqualFunc(got, want, slices.Equal) {
t.Errorf("lines whose error names the refused connection = %v, "+
"want %v", got, want)
}
}