diff --git a/notify/pagerduty/pagerduty.go b/notify/pagerduty/pagerduty.go index 7d85392bb1..a145135bba 100644 --- a/notify/pagerduty/pagerduty.go +++ b/notify/pagerduty/pagerduty.go @@ -215,8 +215,8 @@ func (n *Notifier) notifyV2( RoutingKey: tmpl(string(n.conf.RoutingKey)), EventAction: eventType, DedupKey: key.Hash(), - Images: make([]pagerDutyImage, len(n.conf.Images)), - Links: make([]pagerDutyLink, len(n.conf.Links)), + Images: make([]pagerDutyImage, 0, len(n.conf.Images)), + Links: make([]pagerDutyLink, 0, len(n.conf.Links)), Payload: &pagerDutyPayload{ Summary: summary, Source: tmpl(n.conf.Client), @@ -228,15 +228,27 @@ func (n *Notifier) notifyV2( }, } - for index, item := range n.conf.Images { - msg.Images[index].Src = tmpl(item.Src) - msg.Images[index].Alt = tmpl(item.Alt) - msg.Images[index].Href = tmpl(item.Href) + for _, item := range n.conf.Images { + image := pagerDutyImage{ + Src: tmpl(item.Src), + Alt: tmpl(item.Alt), + Href: tmpl(item.Href), + } + + if image.Src != "" { + msg.Images = append(msg.Images, image) + } } - for index, item := range n.conf.Links { - msg.Links[index].HRef = tmpl(item.Href) - msg.Links[index].Text = tmpl(item.Text) + for _, item := range n.conf.Links { + link := pagerDutyLink{ + HRef: tmpl(item.Href), + Text: tmpl(item.Text), + } + + if link.HRef != "" { + msg.Links = append(msg.Links, link) + } } if tmplErr != nil { diff --git a/notify/pagerduty/pagerduty_test.go b/notify/pagerduty/pagerduty_test.go index 64fac902a4..0830923628 100644 --- a/notify/pagerduty/pagerduty_test.go +++ b/notify/pagerduty/pagerduty_test.go @@ -322,3 +322,129 @@ func TestEventSizeEnforcement(t *testing.T) { require.NoError(t, err) require.Contains(t, encodedV2.String(), `"custom_details":{"error":"Custom details have been removed because the original event exceeds the maximum size of 512KB"}`) } + +func TestPagerDutyEmptySrcHref(t *testing.T) { + type pagerDutyEvent struct { + RoutingKey string `json:"routing_key"` + EventAction string `json:"event_action"` + DedupKey string `json:"dedup_key"` + Payload pagerDutyPayload `json:"payload"` + Images []pagerDutyImage + Links []pagerDutyLink + } + + images := []config.PagerdutyImage{ + { + Src: "", + Alt: "Empty src", + Href: "https://example.com/", + }, + { + Src: "https://example.com/cat.jpg", + Alt: "Empty href", + Href: "", + }, + { + Src: "https://example.com/cat.jpg", + Alt: "", + Href: "https://example.com/", + }, + } + + links := []config.PagerdutyLink{ + { + Href: "", + Text: "Empty href", + }, + { + Href: "https://example.com/", + Text: "", + }, + } + + expectedImages := make([]pagerDutyImage, 0, len(images)) + for _, image := range images { + if image.Src == "" { + continue + } + expectedImages = append(expectedImages, pagerDutyImage{ + Src: image.Src, + Alt: image.Alt, + Href: image.Href, + }) + } + + expectedLinks := make([]pagerDutyLink, 0, len(links)) + for _, link := range links { + if link.Href == "" { + continue + } + expectedLinks = append(expectedLinks, pagerDutyLink{ + HRef: link.Href, + Text: link.Text, + }) + } + + server := httptest.NewServer(http.HandlerFunc( + func(w http.ResponseWriter, r *http.Request) { + decoder := json.NewDecoder(r.Body) + var event pagerDutyEvent + if err := decoder.Decode(&event); err != nil { + panic(err) + } + + if event.RoutingKey == "" || event.EventAction == "" { + http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest) + return + } + + for _, image := range event.Images { + if image.Src == "" { + http.Error(w, "Event object is invalid: 'image src' is missing or blank", http.StatusBadRequest) + return + } + } + + for _, link := range event.Links { + if link.HRef == "" { + http.Error(w, "Event object is invalid: 'link href' is missing or blank", http.StatusBadRequest) + return + } + } + + require.Equal(t, expectedImages, event.Images) + require.Equal(t, expectedLinks, event.Links) + }, + )) + defer server.Close() + + url, err := url.Parse(server.URL) + require.NoError(t, err) + + pagerDutyConfig := config.PagerdutyConfig{ + HTTPConfig: &commoncfg.HTTPClientConfig{}, + RoutingKey: config.Secret("01234567890123456789012345678901"), + URL: &config.URL{URL: url}, + Images: images, + Links: links, + } + + pagerDuty, err := New(&pagerDutyConfig, test.CreateTmpl(t), log.NewNopLogger()) + require.NoError(t, err) + + ctx := context.Background() + ctx = notify.WithGroupKey(ctx, "1") + + _, err = pagerDuty.Notify(ctx, []*types.Alert{ + { + Alert: model.Alert{ + Labels: model.LabelSet{ + "lbl1": "val1", + }, + StartsAt: time.Now(), + EndsAt: time.Now().Add(time.Hour), + }, + }, + }...) + require.NoError(t, err) +}