From 2f78b0da58496e5096b16797da59936bc009a6f7 Mon Sep 17 00:00:00 2001 From: Danielle Maywood Date: Wed, 26 Mar 2025 10:55:10 +0000 Subject: [PATCH] fix: prevent password reset notifications ending up in coder inbox We do not want password reset notifications to end up in Coder Inbox as this doesn't make much sense. This implements the logic to ensure they are not delivered if the method is Coder Inbox. In the future we might want to investigate a better solution but for now this works. --- coderd/notifications/enqueuer.go | 7 ++ coderd/notifications/notifications_test.go | 77 ++++++++++++++++++++++ 2 files changed, 84 insertions(+) diff --git a/coderd/notifications/enqueuer.go b/coderd/notifications/enqueuer.go index 7692bbd85ce07..ff3af3fc5eaa1 100644 --- a/coderd/notifications/enqueuer.go +++ b/coderd/notifications/enqueuer.go @@ -116,6 +116,13 @@ func (s *StoreEnqueuer) EnqueueWithData(ctx context.Context, userID, templateID uuids := make([]uuid.UUID, 0, 2) for _, method := range methods { + // TODO(DanielleMaywood): + // We should have a more permanent solution in the future, but for now this will work. + // We do not want password reset notifications to end up in Coder Inbox. + if method == database.NotificationMethodInbox && templateID == TemplateUserRequestedOneTimePasscode { + continue + } + id := uuid.New() err = s.store.EnqueueNotificationMessage(ctx, database.EnqueueNotificationMessageParams{ ID: id, diff --git a/coderd/notifications/notifications_test.go b/coderd/notifications/notifications_test.go index 9bf31384234ed..60858f1b641b1 100644 --- a/coderd/notifications/notifications_test.go +++ b/coderd/notifications/notifications_test.go @@ -1952,6 +1952,83 @@ func TestNotificationTargetMatrix(t *testing.T) { } } +func TestNotificationOneTimePasswordDeliveryTargets(t *testing.T) { + t.Parallel() + + t.Run("Inbox", func(t *testing.T) { + t.Parallel() + + // nolint:gocritic // Unit test. + ctx := dbauthz.AsNotifier(testutil.Context(t, testutil.WaitSuperLong)) + store, _ := dbtestutil.NewDB(t) + logger := testutil.Logger(t) + + // Given: Coder Inbox is enabled and SMTP/Webhook are disabled. + cfg := defaultNotificationsConfig(database.NotificationMethodSmtp) + cfg.Inbox.Enabled = true + cfg.SMTP = codersdk.NotificationsEmailConfig{} + cfg.Webhook = codersdk.NotificationsWebhookConfig{} + + enq, err := notifications.NewStoreEnqueuer(cfg, store, defaultHelpers(), logger.Named("enqueuer"), quartz.NewMock(t)) + require.NoError(t, err) + user := createSampleUser(t, store) + + // When: A one-time-passcode notification is sent, it does not enqueue a notification. + enqueued, err := enq.Enqueue(ctx, user.ID, notifications.TemplateUserRequestedOneTimePasscode, + map[string]string{"one_time_passcode": "1234"}, "test", user.ID) + require.NoError(t, err) + require.Len(t, enqueued, 0) + }) + + t.Run("SMTP", func(t *testing.T) { + t.Parallel() + + // nolint:gocritic // Unit test. + ctx := dbauthz.AsNotifier(testutil.Context(t, testutil.WaitSuperLong)) + store, _ := dbtestutil.NewDB(t) + logger := testutil.Logger(t) + + // Given: Coder Inbox/Webhook are disabled and SMTP is enabled. + cfg := defaultNotificationsConfig(database.NotificationMethodSmtp) + cfg.Inbox.Enabled = false + cfg.Webhook = codersdk.NotificationsWebhookConfig{} + + enq, err := notifications.NewStoreEnqueuer(cfg, store, defaultHelpers(), logger.Named("enqueuer"), quartz.NewMock(t)) + require.NoError(t, err) + user := createSampleUser(t, store) + + // When: A one-time-passcode notification is sent, it does enqueue a notification. + enqueued, err := enq.Enqueue(ctx, user.ID, notifications.TemplateUserRequestedOneTimePasscode, + map[string]string{"one_time_passcode": "1234"}, "test", user.ID) + require.NoError(t, err) + require.Len(t, enqueued, 1) + }) + + t.Run("Webhook", func(t *testing.T) { + t.Parallel() + + // nolint:gocritic // Unit test. + ctx := dbauthz.AsNotifier(testutil.Context(t, testutil.WaitSuperLong)) + store, _ := dbtestutil.NewDB(t) + logger := testutil.Logger(t) + + // Given: Coder Inbox/SMTP are disabled and Webhook is enabled. + cfg := defaultNotificationsConfig(database.NotificationMethodWebhook) + cfg.Inbox.Enabled = false + cfg.SMTP = codersdk.NotificationsEmailConfig{} + + enq, err := notifications.NewStoreEnqueuer(cfg, store, defaultHelpers(), logger.Named("enqueuer"), quartz.NewMock(t)) + require.NoError(t, err) + user := createSampleUser(t, store) + + // When: A one-time-passcode notification is sent, it does enqueue a notification. + enqueued, err := enq.Enqueue(ctx, user.ID, notifications.TemplateUserRequestedOneTimePasscode, + map[string]string{"one_time_passcode": "1234"}, "test", user.ID) + require.NoError(t, err) + require.Len(t, enqueued, 1) + }) +} + type fakeHandler struct { mu sync.RWMutex succeeded, failed []string