aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAleksandr Nogikh <nogikh@google.com>2025-07-09 16:07:34 +0200
committerAleksandr Nogikh <nogikh@google.com>2025-07-10 08:52:48 +0000
commit33ffce52a3b573ac252d419c0ff3c956028650ad (patch)
treeff09c322549de47a20a9831199653aaee2ec02d4
parent57f1247687b19d8e06b4bdc5a560565665403e08 (diff)
dashboard: keep bug ID in Cc of forwarded emails
When we forward an email that matched an inbox regexp, make sure the author and the original report email are Cc'd. Otherwise the automation cannot determine the original bug report. Improve tests.
-rw-r--r--dashboard/app/email_test.go14
-rw-r--r--dashboard/app/reporting_email.go23
2 files changed, 26 insertions, 11 deletions
diff --git a/dashboard/app/email_test.go b/dashboard/app/email_test.go
index 219c7795e..3c7a2d200 100644
--- a/dashboard/app/email_test.go
+++ b/dashboard/app/email_test.go
@@ -1420,7 +1420,8 @@ func TestForwardEmailInbox(t *testing.T) {
}
t.Run("forwarded", func(t *testing.T) {
- c.incomingEmail("syzbot+prefixABCD@testapp.appspotmail.com",
+ from := "syzbot+prefixABCD@testapp.appspotmail.com"
+ c.incomingEmail(from,
"#syz invalid",
EmailOptMessageID(1),
EmailOptFrom("someone@mail.com"),
@@ -1428,8 +1429,9 @@ func TestForwardEmailInbox(t *testing.T) {
msg := c.pollEmailBug()
require.NotNil(t, msg)
assert.Equal(t, `"syzbot" <syzbot@testapp.appspotmail.com>`, msg.Sender)
- assert.ElementsMatch(t, []string{"forward@a.com", "forward@b.com", "someone@mail.com"},
+ assert.ElementsMatch(t, []string{"forward@a.com", "forward@b.com"},
msg.To, "must be sent to the author and the missing lists")
+ assert.ElementsMatch(t, []string{"\"syzbot\" <" + from + ">", "someone@mail.com"}, msg.Cc)
assert.Equal(t, "<1>", msg.Headers.Get("In-Reply-To"))
assert.Equal(t, `For archival purposes, forwarding an incoming command email to
forward@a.com, forward@b.com.
@@ -1441,6 +1443,14 @@ Author: someone@mail.com
#syz invalid
`, msg.Body)
+
+ t.Run("no-loop", func(t *testing.T) {
+ // Ensure that we don't react to our own reply.
+ c.incomingEmail(from, msg.Body,
+ EmailOptFrom(msg.Sender),
+ EmailOptCC(append(append([]string{}, msg.Cc...), msg.To...)))
+ c.expectNoEmail()
+ })
})
t.Run("no command", func(t *testing.T) {
diff --git a/dashboard/app/reporting_email.go b/dashboard/app/reporting_email.go
index a6942a952..78db7fb90 100644
--- a/dashboard/app/reporting_email.go
+++ b/dashboard/app/reporting_email.go
@@ -641,7 +641,7 @@ func matchInbox(c context.Context, myEmail string) *PerInboxConfig {
}
func processInboxEmail(c context.Context, msg *email.Email, inbox *PerInboxConfig) error {
- if len(msg.Commands) == 0 || len(msg.BugIDs) == 0 {
+ if len(msg.Commands) == 0 || len(msg.BugIDs) == 0 || msg.OwnEmail {
// Do not forward emails with no commands.
// Also, we don't care about the emails that don't include any BugIDs.
return nil
@@ -657,6 +657,7 @@ func processInboxEmail(c context.Context, msg *email.Email, inbox *PerInboxConfi
sort.Strings(missing)
if len(missing) == 0 {
// Everything's OK.
+ log.Infof(c, "email %q has all necessary lists in Cc", msg.MessageID)
return nil
}
// We don't want to forward from a name+hash@domain address because
@@ -670,7 +671,7 @@ func processInboxEmail(c context.Context, msg *email.Email, inbox *PerInboxConfi
if !stringInList(msg.Cc, cc) {
msg.Cc = append(msg.Cc, cc)
}
- return forwardEmail(c, msg, missing, "", msg.MessageID, true)
+ return forwardEmail(c, msg, missing, []string{cc, msg.Author}, "", msg.MessageID)
}
// nolint: gocyclo
@@ -734,7 +735,7 @@ func processIncomingEmail(c context.Context, msg *email.Email) error {
}
reply := groupEmailReplies(replies)
if reply == "" && len(msg.Commands) > 0 && len(missingLists) > 0 && !unCc {
- return forwardEmail(c, msg, missingLists, bugInfo.bugReporting.ID, bugInfo.bugReporting.ExtID, false)
+ return forwardEmail(c, msg, missingLists, nil, bugInfo.bugReporting.ID, bugInfo.bugReporting.ExtID)
}
if reply != "" {
return replyTo(c, msg, bugInfo.bugReporting.ID, reply)
@@ -1421,8 +1422,8 @@ func missingMailingLists(c context.Context, msg *email.Email, emailConfig *Email
return missing
}
-func forwardEmail(c context.Context, msg *email.Email, mailingLists []string,
- bugID, inReplyTo string, includeAuthor bool) error {
+func forwardEmail(c context.Context, msg *email.Email, mailingLists, cc []string,
+ bugID, inReplyTo string) error {
log.Infof(c, "forwarding email: id=%q from=%q to=%q", msg.MessageID, msg.Author, mailingLists)
body := fmt.Sprintf(`For archival purposes, forwarding an incoming command email to
%v.
@@ -1437,10 +1438,14 @@ Author: %s
if err != nil {
return err
}
- if includeAuthor {
- mailingLists = append([]string{msg.Author}, mailingLists...)
- }
- return sendMailText(c, msg.Subject, from, mailingLists, inReplyTo, body)
+ return sendEmail(c, &aemail.Message{
+ Sender: from,
+ To: mailingLists,
+ Cc: cc,
+ Subject: msg.Subject,
+ Body: body,
+ Headers: mail.Header{"In-Reply-To": []string{inReplyTo}},
+ })
}
func sendMailText(c context.Context, subject, from string, to []string, replyTo, body string) error {