From d5bebb8408c3fbe456a9b4c63ef735815b5d1673 Mon Sep 17 00:00:00 2001 From: sneak Date: Mon, 24 Aug 2026 15:46:50 +0000 Subject: [PATCH] Render unknown for a zero CreatedAt in Slack/Mattermost messages (closes #298) FormatSlackMessage rendered the Timestamp line unconditionally, so a reaped-row fallback delivery carried "0001-01-01T00:00:00Z" -- the exact string https://git.eeqj.de/sneak/webhooker/issues/257 was filed against, indistinguishable from that regression. When event.CreatedAt.IsZero(), render "unknown" instead; a real CreatedAt still renders as RFC3339. --- internal/delivery/event_timestamp_test.go | 35 +++++++++++++++++++++++ internal/delivery/target_slack.go | 7 ++++- 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/internal/delivery/event_timestamp_test.go b/internal/delivery/event_timestamp_test.go index 87bd07f..09e70cf 100644 --- a/internal/delivery/event_timestamp_test.go +++ b/internal/delivery/event_timestamp_test.go @@ -365,6 +365,41 @@ func TestFormatSlackMessageOverTaskReconstructedEvent( ) } +// TestFormatSlackMessageZeroTimestamp asserts the rendering choice +// directly, without going through the engine: a zero CreatedAt (the +// shape a reaped-row fallback produces) renders as "unknown" rather +// than the year-1 zero time, while a real CreatedAt still renders as +// RFC3339. +func TestFormatSlackMessageZeroTimestamp(t *testing.T) { + t.Parallel() + + zeroEvent := database.Event{ + Method: http.MethodPost, + ContentType: testContentType, + Body: tsEventBody, + } + + zeroText := delivery.FormatSlackMessage(&zeroEvent) + + assert.NotContains(t, zeroText, "0001-01-01", + "slack message carries the zero-time year", + ) + assert.Contains(t, zeroText, "*Timestamp:* `unknown`", + "slack message does not mark an unset receipt time as unknown", + ) + + nonZeroEvent := zeroEvent + nonZeroEvent.CreatedAt = tsEventCreatedAt() + + nonZeroText := delivery.FormatSlackMessage(&nonZeroEvent) + + assert.Contains(t, nonZeroText, + "*Timestamp:* `"+ + tsEventCreatedAt().UTC().Format(time.RFC3339)+"`", + "slack message does not render a real receipt time as RFC3339", + ) +} + // TestEventReconstructionSurvivesAReapedRow pins the fallback: an // event row reaped by retention while its delivery still holds the // body inline is still delivered, with the receipt time unset, diff --git a/internal/delivery/target_slack.go b/internal/delivery/target_slack.go index f10cc15..c2f7ff7 100644 --- a/internal/delivery/target_slack.go +++ b/internal/delivery/target_slack.go @@ -231,10 +231,15 @@ func FormatSlackMessage( event.ContentType, ) + timestamp := "unknown" + if !event.CreatedAt.IsZero() { + timestamp = event.CreatedAt.UTC().Format(time.RFC3339) + } + fmt.Fprintf( &b, "*Timestamp:* `%s`\n", - event.CreatedAt.UTC().Format(time.RFC3339), + timestamp, ) fmt.Fprintf(