Skip to content
Permalink
Browse files

dashboard/app: add uncc command

Add "#syz uncc" command as a safety handle.
The command allows sender to unsubscribe from all future communication on the bug.

Linus mentioned possibility of saying "I'm not the right person for this report"
in the context of bug reminders:
https://groups.google.com/d/msg/syzkaller/zYlQ-b-QPHQ/AJzpeObcBAAJ
  • Loading branch information...
dvyukov committed Mar 21, 2019
1 parent 40fdabd commit ca3ffbc9f365dab1816871c776e673e30a86bcdf
@@ -22,7 +22,7 @@ func TestEmailReport(t *testing.T) {
c.client2.UploadBuild(build)

crash := testCrash(build, 1)
crash.Maintainers = []string{`"Foo Bar" <foo@bar.com>`, `bar@foo.com`}
crash.Maintainers = []string{`"Foo Bar" <foo@bar.com>`, `bar@foo.com`, `idont@want.EMAILS`}
c.client2.ReportCrash(crash)

// Report the crash over email and check all fields.
@@ -52,7 +52,7 @@ console output: %[2]v
kernel config: %[3]v
dashboard link: https://testapp.appspot.com/bug?extid=%[1]v
compiler: compiler1
CC: [bar@foo.com foo@bar.com]
CC: [bar@foo.com foo@bar.com idont@want.EMAILS]
Unfortunately, I don't have any reproducer for this crash yet.
@@ -109,6 +109,14 @@ For more options, visit https://groups.google.com/d/optout.
// We used to extract "#syz fix: exact-commit-title" from it.
c.incomingEmail(sender0, body0)

c.incomingEmail(sender0, "I don't want emails", EmailOptFrom(`"idont" <idont@WANT.emails>`))
c.expectNoEmail()

// This person sends an email and is listed as a maintainer, but opt-out of emails.
// We should not send anything else to them for this bug. Also don't warn about no mailing list in CC.
c.incomingEmail(sender0, "#syz uncc", EmailOptFrom(`"IDONT" <Idont@want.emails>`), EmailOptCC(nil))
c.expectNoEmail()

// Now report syz reproducer and check updated email.
build2 := testBuild(10)
build2.Arch = "386"
@@ -310,8 +318,7 @@ unknown command "bad-command"

// Now mark the bug as fixed.
c.incomingEmail(sender1, "#syz fix: some: commit title")
c.expectOK(c.GET("/email_poll"))
c.expectEQ(len(c.emailSink), 0)
c.expectNoEmail()

// Check that the commit is now passed to builders.
builderPollResp, _ := c.client2.BuilderPoll(build.Manager)
@@ -361,9 +368,6 @@ Content-Type: text/plain
#syz upstream
`, sender)
c.expectOK(c.POST("/_ah/mail/", incoming1))

c.expectOK(c.GET("/email_poll"))
c.expectEQ(len(c.emailSink), 0)
}

// Basic dup scenario: mark one bug as dup of another.
@@ -383,24 +387,25 @@ func TestEmailDup(t *testing.T) {
c.client2.ReportCrash(crash2)

c.expectOK(c.GET("/email_poll"))
c.expectEQ(len(c.emailSink), 2)
msg1 := <-c.emailSink
msg2 := <-c.emailSink
msg1 := c.pollEmailBug()
msg2 := c.pollEmailBug()

// Dup crash2 to crash1.
c.incomingEmail(msg2.Sender, "#syz dup: BUG: slightly more elaborate title")
c.expectOK(c.GET("/email_poll"))
c.expectEQ(len(c.emailSink), 0)
c.expectNoEmail()

// Second crash happens again
crash2.ReproC = []byte("int main() {}")
c.client2.ReportCrash(crash2)
c.expectOK(c.GET("/email_poll"))
c.expectEQ(len(c.emailSink), 0)
c.expectNoEmail()

// Now close the original bug, and check that new bugs for dup are now created.
c.incomingEmail(msg1.Sender, "#syz invalid")

// uncc command must not trugger error reply even for closed bug.
c.incomingEmail(msg1.Sender, "#syz uncc", EmailOptCC(nil))
c.expectNoEmail()

// New crash must produce new bug in the first reporting.
c.client2.ReportCrash(crash2)
{
@@ -425,25 +430,21 @@ func TestEmailUndup(t *testing.T) {
c.client2.ReportCrash(crash2)

c.expectOK(c.GET("/email_poll"))
c.expectEQ(len(c.emailSink), 2)
msg1 := <-c.emailSink
msg2 := <-c.emailSink
msg1 := c.pollEmailBug()
msg2 := c.pollEmailBug()

// Dup crash2 to crash1.
c.incomingEmail(msg2.Sender, "#syz dup: BUG: slightly more elaborate title")
c.expectOK(c.GET("/email_poll"))
c.expectEQ(len(c.emailSink), 0)
c.expectNoEmail()

// Undup crash2.
c.incomingEmail(msg2.Sender, "#syz undup")
c.expectOK(c.GET("/email_poll"))
c.expectEQ(len(c.emailSink), 0)
c.expectNoEmail()

// Now close the original bug, and check that new crashes for the dup does not create bugs.
c.incomingEmail(msg1.Sender, "#syz invalid")
c.client2.ReportCrash(crash2)
c.expectOK(c.GET("/email_poll"))
c.expectEQ(len(c.emailSink), 0)
c.expectNoEmail()
}

func TestEmailCrossReportingDup(t *testing.T) {
@@ -491,13 +492,9 @@ func TestEmailCrossReportingDup(t *testing.T) {

c.incomingEmail(bugSender, "#syz dup: "+crash2.Title)
if test.result {
if len(c.emailSink) != 0 {
msg := <-c.emailSink
t.Fatalf("unexpected reply: %s\n%s\n", msg.Subject, msg.Body)
}
c.expectNoEmail()
} else {
c.expectEQ(len(c.emailSink), 1)
msg := <-c.emailSink
msg := c.pollEmailBug()
if !strings.Contains(msg.Body, "> #syz dup:") ||
!strings.Contains(msg.Body, "Can't dup bug to a bug in different reporting") {
c.t.Fatalf("bad reply body:\n%v", msg.Body)
@@ -512,8 +509,7 @@ func TestEmailErrors(t *testing.T) {

// No reply for email without bug hash and no commands.
c.incomingEmail("syzbot@testapp.appspotmail.com", "Investment Proposal")
c.expectOK(c.GET("/email_poll"))
c.expectEQ(len(c.emailSink), 0)
c.expectNoEmail()

// If email contains a command we need to reply.
c.incomingEmail("syzbot@testapp.appspotmail.com", "#syz invalid")
@@ -89,6 +89,7 @@ type Bug struct {
CommitInfo []Commit // additional info for commits (for historical reasons parallel array to Commits)
HappenedOn []string `datastore:",noindex"` // list of managers
PatchedOn []string `datastore:",noindex"` // list of managers
UNCC []string // don't CC these emails on this bug
}

type Commit struct {
@@ -572,10 +572,6 @@ func createBugReportForJob(c context.Context, job *Job, jobKey *datastore.Key, c
if err != nil {
return nil, err
}
kernelConfig, _, err := getText(c, textKernelConfig, build.KernelConfig)
if err != nil {
return nil, err
}
bugKey := jobKey.Parent()
crashKey := datastore.NewKey(c, "Crash", "", job.CrashID, bugKey)
crash := new(Crash)
@@ -590,10 +586,6 @@ func createBugReportForJob(c context.Context, job *Job, jobKey *datastore.Key, c
if bugReporting == nil {
return nil, fmt.Errorf("job bug has no reporting %q", job.Reporting)
}
creditEmail, err := email.AddAddrContext(ownEmail(c), bugReporting.ID)
if err != nil {
return nil, err
}
var typ dashapi.ReportType
switch job.Type {
case JobTestPatch:
@@ -606,39 +598,21 @@ func createBugReportForJob(c context.Context, job *Job, jobKey *datastore.Key, c
return nil, fmt.Errorf("unknown job type %v", job.Type)
}
rep := &dashapi.BugReport{
Type: typ,
Namespace: job.Namespace,
Config: reportingConfig,
ID: bugReporting.ID,
JobID: extJobID(jobKey),
ExtID: job.ExtID,
Title: bug.displayTitle(),
Link: fmt.Sprintf("%v/bug?extid=%v", appURL(c), bugReporting.ID),
CreditEmail: creditEmail,
CC: job.CC,
Log: crashLog,
LogLink: externalLink(c, textCrashLog, job.CrashLog),
Report: report,
ReportLink: externalLink(c, textCrashReport, job.CrashReport),
OS: build.OS,
Arch: build.Arch,
VMArch: build.VMArch,
UserSpaceArch: kernelArch(build.Arch),
CompilerID: build.CompilerID,
KernelRepo: build.KernelRepo,
KernelRepoAlias: kernelRepoInfo(build).Alias,
KernelBranch: build.KernelBranch,
KernelCommit: build.KernelCommit,
KernelCommitTitle: build.KernelCommitTitle,
KernelCommitDate: build.KernelCommitDate,
KernelConfig: kernelConfig,
KernelConfigLink: externalLink(c, textKernelConfig, build.KernelConfig),
ReproCLink: externalLink(c, textReproC, crash.ReproC),
ReproSyzLink: externalLink(c, textReproSyz, crash.ReproSyz),
CrashTitle: job.CrashTitle,
Error: jobError,
ErrorLink: externalLink(c, textError, job.Error),
PatchLink: externalLink(c, textPatch, job.Patch),
Type: typ,
Config: reportingConfig,
JobID: extJobID(jobKey),
ExtID: job.ExtID,
CC: job.CC,
Log: crashLog,
LogLink: externalLink(c, textCrashLog, job.CrashLog),
Report: report,
ReportLink: externalLink(c, textCrashReport, job.CrashReport),
ReproCLink: externalLink(c, textReproC, crash.ReproC),
ReproSyzLink: externalLink(c, textReproSyz, crash.ReproSyz),
CrashTitle: job.CrashTitle,
Error: jobError,
ErrorLink: externalLink(c, textError, job.Error),
PatchLink: externalLink(c, textPatch, job.Patch),
}
if job.Type == JobBisectCause || job.Type == JobBisectFix {
kernelRepo := kernelRepoInfo(build)
@@ -659,6 +633,9 @@ func createBugReportForJob(c context.Context, job *Job, jobKey *datastore.Key, c
rep.Error = rep.Error[len(rep.Error)-maxInlineError:]
rep.ErrorTruncated = true
}
if err := fillBugReport(c, rep, bug, bugReporting, build); err != nil {
return nil, err
}
return rep, nil
}

@@ -74,24 +74,21 @@ func TestJob(t *testing.T) {

c.incomingEmail(sender, "#syz test: git://git.git/git.git kernel-branch\n"+patch,
EmailOptFrom("\"foo\" <blAcklisteD@dOmain.COM>"))
c.expectOK(c.GET("/email_poll"))
c.expectEQ(len(c.emailSink), 0)
c.expectNoEmail()
pollResp := c.client2.pollJobs(build.Manager)
c.expectEQ(pollResp.ID, "")

// This submits actual test request.
c.incomingEmail(sender, "#syz test: git://git.git/git.git kernel-branch\n"+patch,
EmailOptMessageID(1), EmailOptFrom("test@requester.com"),
EmailOptCC([]string{"somebody@else.com"}))
c.expectOK(c.GET("/email_poll"))
c.expectEQ(len(c.emailSink), 0)
c.expectNoEmail()

// A dup of the same request with the same Message-ID.
c.incomingEmail(sender, "#syz test: git://git.git/git.git kernel-branch\n"+patch,
EmailOptMessageID(1), EmailOptFrom("test@requester.com"),
EmailOptCC([]string{"somebody@else.com"}))
c.expectOK(c.GET("/email_poll"))
c.expectEQ(len(c.emailSink), 0)
c.expectNoEmail()

pollResp = c.client2.pollJobs("foobar")
c.expectEQ(pollResp.ID, "")
@@ -27,8 +27,7 @@ func TestEmailNotifUpstreamEmbargo(t *testing.T) {

// Upstreaming happens after 14 days, so no emails yet.
c.advanceTime(13 * 24 * time.Hour)
c.expectOK(c.GET("/email_poll"))
c.expectEQ(len(c.emailSink), 0)
c.expectNoEmail()

// Now we should get notification about upstreaming and upstream report:
c.advanceTime(2 * 24 * time.Hour)
@@ -54,8 +53,7 @@ func TestEmailNotifUpstreamSkip(t *testing.T) {
c.expectEQ(report.To, []string{"test@syzkaller.com"})

// No emails yet.
c.expectOK(c.GET("/email_poll"))
c.expectEQ(len(c.emailSink), 0)
c.expectNoEmail()

// Now upload repro and it should be auto-upstreamed.
crash.ReproOpts = []byte("repro opts")
@@ -82,25 +80,21 @@ func TestEmailNotifBadFix(t *testing.T) {
c.expectEQ(report.To, []string{"test@syzkaller.com"})

c.incomingEmail(report.Sender, "#syz fix: some: commit title")
c.expectOK(c.GET("/email_poll"))
c.expectEQ(len(c.emailSink), 0)
c.expectNoEmail()

// Notification about bad fixing commit should be send after 90 days.
c.advanceTime(50 * 24 * time.Hour)
c.expectOK(c.GET("/email_poll"))
c.expectEQ(len(c.emailSink), 0)
c.expectNoEmail()
c.advanceTime(35 * 24 * time.Hour)
c.expectOK(c.GET("/email_poll"))
c.expectEQ(len(c.emailSink), 0)
c.expectNoEmail()
c.advanceTime(10 * 24 * time.Hour)
notif := c.pollEmailBug()
if !strings.Contains(notif.Body, "This bug is marked as fixed by commit:\nsome: commit title\n") {
t.Fatalf("bad notification text: %q", notif.Body)
}
// No notifications for another 14 days, then another one.
c.advanceTime(13 * 24 * time.Hour)
c.expectOK(c.GET("/email_poll"))
c.expectEQ(len(c.emailSink), 0)
c.expectNoEmail()
c.advanceTime(2 * 24 * time.Hour)
notif = c.pollEmailBug()
if !strings.Contains(notif.Body, "This bug is marked as fixed by commit:\nsome: commit title\n") {
@@ -127,13 +121,11 @@ func TestEmailNotifObsoleted(t *testing.T) {

// Bug is open, new crashes don't create new bug.
c.client2.ReportCrash(crash)
c.expectOK(c.GET("/email_poll"))
c.expectEQ(len(c.emailSink), 0)
c.expectNoEmail()

// Not yet.
c.advanceTime(179 * 24 * time.Hour)
c.expectOK(c.GET("/email_poll"))
c.expectEQ(len(c.emailSink), 0)
c.expectNoEmail()

// Now!
c.advanceTime(2 * 24 * time.Hour)
@@ -199,8 +191,7 @@ func TestEmailNotifNotObsoleted(t *testing.T) {
report4 = c.pollEmailBug()

c.advanceTime(179 * 24 * time.Hour)
c.expectOK(c.GET("/email_poll"))
c.expectEQ(len(c.emailSink), 0)
c.expectNoEmail()

c.client2.ReportCrash(crash2)
c.incomingEmail(report3.Sender, "I am looking at it")
@@ -209,8 +200,7 @@ func TestEmailNotifNotObsoleted(t *testing.T) {
// Only crash 4 is obsoleted.
notif := c.pollEmailBug()
c.expectEQ(notif.Sender, report4.Sender)
c.expectOK(c.GET("/email_poll"))
c.expectEQ(len(c.emailSink), 0)
c.expectNoEmail()

// Crash 3 also obsoleted after some time.
c.advanceTime(20 * 24 * time.Hour)

0 comments on commit ca3ffbc

Please sign in to comment.
You can’t perform that action at this time.