github.com/google/syzkaller@v0.0.0-20240517125934-c0f1611a36d6/dashboard/app/email_test.go (about) 1 // Copyright 2017 syzkaller project authors. All rights reserved. 2 // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. 3 4 package main 5 6 import ( 7 "context" 8 "fmt" 9 "strings" 10 "testing" 11 "time" 12 13 "github.com/google/syzkaller/dashboard/dashapi" 14 "github.com/google/syzkaller/pkg/email" 15 "github.com/google/syzkaller/sys/targets" 16 "github.com/stretchr/testify/assert" 17 ) 18 19 // nolint: funlen 20 func TestEmailReport(t *testing.T) { 21 c := NewCtx(t) 22 defer c.Close() 23 24 build := testBuild(1) 25 c.client2.UploadBuild(build) 26 27 crash := testCrash(build, 1) 28 crash.Maintainers = []string{`"Foo Bar" <foo@bar.com>`, `bar@foo.com`, `idont@want.EMAILS`} 29 c.client2.ReportCrash(crash) 30 31 // Report the crash over email and check all fields. 32 var sender0, extBugID0, body0 string 33 var dbBug0 *Bug 34 { 35 msg := c.pollEmailBug() 36 sender0 = msg.Sender 37 body0 = msg.Body 38 sender, extBugID, err := email.RemoveAddrContext(msg.Sender) 39 c.expectOK(err) 40 extBugID0 = extBugID 41 dbBug, dbCrash, dbBuild := c.loadBug(extBugID0) 42 dbBug0 = dbBug 43 crashLogLink := externalLink(c.ctx, textCrashLog, dbCrash.Log) 44 kernelConfigLink := externalLink(c.ctx, textKernelConfig, dbBuild.KernelConfig) 45 c.expectEQ(sender, fromAddr(c.ctx)) 46 to := c.config().Namespaces["test2"].Reporting[0].Config.(*EmailConfig).Email 47 c.expectEQ(msg.To, []string{to}) 48 c.expectEQ(msg.Subject, crash.Title) 49 c.expectEQ(len(msg.Attachments), 0) 50 c.expectEQ(msg.Body, fmt.Sprintf(`Hello, 51 52 syzbot found the following issue on: 53 54 HEAD commit: 111111111111 kernel_commit_title1 55 git tree: repo1 branch1 56 console output: %[2]v 57 kernel config: %[3]v 58 dashboard link: https://testapp.appspot.com/bug?extid=%[1]v 59 compiler: compiler1 60 CC: [bar@foo.com foo@bar.com idont@want.EMAILS] 61 62 Unfortunately, I don't have any reproducer for this issue yet. 63 64 IMPORTANT: if you fix the issue, please add the following tag to the commit: 65 Reported-by: syzbot+%[1]v@testapp.appspotmail.com 66 67 report1 68 69 --- 70 This report is generated by a bot. It may contain errors. 71 See https://goo.gl/tpsmEJ for more information about syzbot. 72 syzbot engineers can be reached at syzkaller@googlegroups.com. 73 74 syzbot will keep track of this issue. See: 75 https://goo.gl/tpsmEJ#status for how to communicate with syzbot. 76 77 If the report is already addressed, let syzbot know by replying with: 78 #syz fix: exact-commit-title 79 80 If you want to overwrite report's subsystems, reply with: 81 #syz set subsystems: new-subsystem 82 (See the list of subsystem names on the web dashboard) 83 84 If the report is a duplicate of another one, reply with: 85 #syz dup: exact-subject-of-another-report 86 87 If you want to undo deduplication, reply with: 88 #syz undup`, 89 extBugID0, crashLogLink, kernelConfigLink)) 90 c.checkURLContents(crashLogLink, crash.Log) 91 c.checkURLContents(kernelConfigLink, build.KernelConfig) 92 } 93 94 // Emulate receive of the report from a mailing list. 95 // This should update the bug with the link/Message-ID. 96 // nolint: lll 97 incoming1 := fmt.Sprintf(`Sender: syzkaller@googlegroups.com 98 Date: Tue, 15 Aug 2017 14:59:00 -0700 99 Message-ID: <1234> 100 Subject: crash1 101 From: %v 102 To: foo@bar.com 103 Content-Type: text/plain 104 105 Hello 106 107 syzbot will keep track of this issue. 108 If you forgot to add the Reported-by tag, once the fix for this bug is merged 109 into any tree, please reply to this email with: 110 #syz fix: exact-commit-title 111 To mark this as a duplicate of another syzbot report, please reply with: 112 #syz dup: exact-subject-of-another-report 113 If it's a one-off invalid bug report, please reply with: 114 #syz invalid 115 116 -- 117 You received this message because you are subscribed to the Google Groups "syzkaller" group. 118 To unsubscribe from this group and stop receiving emails from it, send an email to syzkaller+unsubscribe@googlegroups.com. 119 To post to this group, send email to syzkaller@googlegroups.com. 120 To view this discussion on the web visit https://groups.google.com/d/msgid/syzkaller/1234@google.com. 121 For more options, visit https://groups.google.com/d/optout. 122 `, sender0) 123 124 _, err := c.POST("/_ah/mail/", incoming1) 125 c.expectOK(err) 126 127 // Emulate that somebody sends us our own email back without quoting. 128 // We used to extract "#syz fix: exact-commit-title" from it. 129 c.incomingEmail(sender0, body0) 130 131 c.incomingEmail(sender0, "I don't want emails", EmailOptFrom(`"idont" <idont@WANT.emails>`)) 132 c.expectNoEmail() 133 134 // This person sends an email and is listed as a maintainer, but opt-out of emails. 135 // We should not send anything else to them for this bug. Also don't warn about no mailing list in CC. 136 c.incomingEmail(sender0, "#syz uncc", EmailOptFrom(`"IDONT" <Idont@want.emails>`), EmailOptCC(nil)) 137 c.expectNoEmail() 138 139 // Now report syz reproducer and check updated email. 140 build2 := testBuild(10) 141 build2.Arch = targets.I386 142 build2.KernelRepo = testConfig.Namespaces["test2"].Repos[0].URL 143 build2.KernelBranch = testConfig.Namespaces["test2"].Repos[0].Branch 144 build2.KernelCommitTitle = "a really long title, longer than 80 chars, really long-long-long-long-long-long title" 145 c.client2.UploadBuild(build2) 146 crash.BuildID = build2.ID 147 crash.ReproOpts = []byte("repro opts") 148 crash.ReproSyz = []byte("getpid()") 149 syzRepro := []byte(fmt.Sprintf("# https://testapp.appspot.com/bug?id=%v\n%s#%s\n%s", 150 dbBug0.keyHash(c.ctx), syzReproPrefix, crash.ReproOpts, crash.ReproSyz)) 151 c.client2.ReportCrash(crash) 152 153 { 154 msg := c.pollEmailBug() 155 c.expectEQ(msg.Sender, sender0) 156 sender, _, err := email.RemoveAddrContext(msg.Sender) 157 c.expectOK(err) 158 _, dbCrash, dbBuild := c.loadBug(extBugID0) 159 reproSyzLink := externalLink(c.ctx, textReproSyz, dbCrash.ReproSyz) 160 crashLogLink := externalLink(c.ctx, textCrashLog, dbCrash.Log) 161 kernelConfigLink := externalLink(c.ctx, textKernelConfig, dbBuild.KernelConfig) 162 c.expectEQ(sender, fromAddr(c.ctx)) 163 to := []string{ 164 "always@cc.me", 165 "bugs2@syzkaller.com", 166 "bugs@syzkaller.com", // This is from incomingEmail. 167 "default@sender.com", // This is from incomingEmail. 168 "foo@bar.com", 169 c.config().Namespaces["test2"].Reporting[0].Config.(*EmailConfig).Email, 170 } 171 c.expectEQ(msg.To, to) 172 c.expectEQ(msg.Subject, "Re: "+crash.Title) 173 c.expectEQ(len(msg.Attachments), 0) 174 c.expectEQ(msg.Headers["In-Reply-To"], []string{"<1234>"}) 175 c.expectEQ(msg.Body, fmt.Sprintf(`syzbot has found a reproducer for the following issue on: 176 177 HEAD commit: 101010101010 a really long title, longer than 80 chars, re.. 178 git tree: repo10alias 179 console output: %[3]v 180 kernel config: %[4]v 181 dashboard link: https://testapp.appspot.com/bug?extid=%[1]v 182 compiler: compiler10 183 userspace arch: i386 184 syz repro: %[2]v 185 CC: [bar@foo.com foo@bar.com maintainers@repo10.org bugs@repo10.org] 186 187 IMPORTANT: if you fix the issue, please add the following tag to the commit: 188 Reported-by: syzbot+%[1]v@testapp.appspotmail.com 189 190 report1 191 192 --- 193 If you want syzbot to run the reproducer, reply with: 194 #syz test: git://repo/address.git branch-or-commit-hash 195 If you attach or paste a git patch, syzbot will apply it before testing. 196 `, extBugID0, reproSyzLink, crashLogLink, kernelConfigLink)) 197 c.checkURLContents(reproSyzLink, syzRepro) 198 c.checkURLContents(crashLogLink, crash.Log) 199 c.checkURLContents(kernelConfigLink, build2.KernelConfig) 200 } 201 202 // Now upstream the bug and check that it reaches the next reporting. 203 c.incomingEmail(sender0, "#syz upstream") 204 205 sender1, extBugID1 := "", "" 206 { 207 msg := c.pollEmailBug() 208 sender1 = msg.Sender 209 c.expectNE(sender1, sender0) 210 sender, extBugID, err := email.RemoveAddrContext(msg.Sender) 211 c.expectOK(err) 212 extBugID1 = extBugID 213 _, dbCrash, dbBuild := c.loadBug(extBugID1) 214 reproSyzLink := externalLink(c.ctx, textReproSyz, dbCrash.ReproSyz) 215 crashLogLink := externalLink(c.ctx, textCrashLog, dbCrash.Log) 216 kernelConfigLink := externalLink(c.ctx, textKernelConfig, dbBuild.KernelConfig) 217 c.expectEQ(sender, fromAddr(c.ctx)) 218 c.expectEQ(msg.To, []string{ 219 "always@cc.me", 220 "bar@foo.com", 221 "bugs@repo10.org", 222 "bugs@syzkaller.com", 223 "default@maintainers.com", 224 "foo@bar.com", 225 "maintainers@repo10.org", 226 }) 227 c.expectEQ(msg.Subject, "[syzbot] "+crash.Title) 228 c.expectEQ(len(msg.Attachments), 0) 229 c.expectEQ(msg.Body, fmt.Sprintf(`Hello, 230 231 syzbot found the following issue on: 232 233 HEAD commit: 101010101010 a really long title, longer than 80 chars, re.. 234 git tree: repo10alias 235 console output: %[3]v 236 kernel config: %[4]v 237 dashboard link: https://testapp.appspot.com/bug?extid=%[1]v 238 compiler: compiler10 239 userspace arch: i386 240 syz repro: %[2]v 241 CC: [bar@foo.com foo@bar.com maintainers@repo10.org bugs@repo10.org] 242 243 IMPORTANT: if you fix the issue, please add the following tag to the commit: 244 Reported-by: syzbot+%[1]v@testapp.appspotmail.com 245 246 report1 247 248 --- 249 This report is generated by a bot. It may contain errors. 250 See https://goo.gl/tpsmEJ for more information about syzbot. 251 syzbot engineers can be reached at syzkaller@googlegroups.com. 252 253 syzbot will keep track of this issue. See: 254 https://goo.gl/tpsmEJ#status for how to communicate with syzbot. 255 256 If the report is already addressed, let syzbot know by replying with: 257 #syz fix: exact-commit-title 258 259 If you want syzbot to run the reproducer, reply with: 260 #syz test: git://repo/address.git branch-or-commit-hash 261 If you attach or paste a git patch, syzbot will apply it before testing. 262 263 If you want to overwrite report's subsystems, reply with: 264 #syz set subsystems: new-subsystem 265 (See the list of subsystem names on the web dashboard) 266 267 If the report is a duplicate of another one, reply with: 268 #syz dup: exact-subject-of-another-report 269 270 If you want to undo deduplication, reply with: 271 #syz undup`, 272 extBugID1, reproSyzLink, crashLogLink, kernelConfigLink)) 273 c.checkURLContents(reproSyzLink, syzRepro) 274 c.checkURLContents(crashLogLink, crash.Log) 275 c.checkURLContents(kernelConfigLink, build2.KernelConfig) 276 } 277 278 // Model that somebody adds more emails to CC list. 279 incoming3 := fmt.Sprintf(`Sender: syzkaller@googlegroups.com 280 Date: Tue, 15 Aug 2017 14:59:00 -0700 281 Message-ID: <1234> 282 Subject: crash1 283 From: foo@bar.com 284 To: %v 285 CC: new@new.com, "another" <another@another.com>, bar@foo.com, bugs@syzkaller.com, foo@bar.com 286 Content-Type: text/plain 287 288 +more people 289 `, sender1) 290 291 _, err = c.POST("/_ah/mail/", incoming3) 292 c.expectOK(err) 293 294 // Now upload a C reproducer. 295 crash.ReproC = []byte("int main() {}") 296 crash.Maintainers = []string{"\"qux\" <qux@qux.com>"} 297 c.client2.ReportCrash(crash) 298 cRepro := []byte(fmt.Sprintf("// https://testapp.appspot.com/bug?id=%v\n%s", 299 dbBug0.keyHash(c.ctx), crash.ReproC)) 300 301 { 302 msg := c.pollEmailBug() 303 c.expectEQ(msg.Sender, sender1) 304 sender, _, err := email.RemoveAddrContext(msg.Sender) 305 c.expectOK(err) 306 _, dbCrash, dbBuild := c.loadBug(extBugID1) 307 reproCLink := externalLink(c.ctx, textReproC, dbCrash.ReproC) 308 reproSyzLink := externalLink(c.ctx, textReproSyz, dbCrash.ReproSyz) 309 crashLogLink := externalLink(c.ctx, textCrashLog, dbCrash.Log) 310 kernelConfigLink := externalLink(c.ctx, textKernelConfig, dbBuild.KernelConfig) 311 c.expectEQ(sender, fromAddr(c.ctx)) 312 c.expectEQ(msg.To, []string{ 313 "always@cc.me", 314 "another@another.com", "bar@foo.com", "bugs@repo10.org", 315 "bugs@syzkaller.com", "default@maintainers.com", "foo@bar.com", 316 "maintainers@repo10.org", "new@new.com", "qux@qux.com"}) 317 c.expectEQ(msg.Subject, "Re: [syzbot] "+crash.Title) 318 c.expectEQ(len(msg.Attachments), 0) 319 c.expectEQ(msg.Body, fmt.Sprintf(`syzbot has found a reproducer for the following issue on: 320 321 HEAD commit: 101010101010 a really long title, longer than 80 chars, re.. 322 git tree: repo10alias 323 console output: %[4]v 324 kernel config: %[5]v 325 dashboard link: https://testapp.appspot.com/bug?extid=%[1]v 326 compiler: compiler10 327 userspace arch: i386 328 syz repro: %[3]v 329 C reproducer: %[2]v 330 CC: [qux@qux.com maintainers@repo10.org bugs@repo10.org] 331 332 IMPORTANT: if you fix the issue, please add the following tag to the commit: 333 Reported-by: syzbot+%[1]v@testapp.appspotmail.com 334 335 report1 336 337 --- 338 If you want syzbot to run the reproducer, reply with: 339 #syz test: git://repo/address.git branch-or-commit-hash 340 If you attach or paste a git patch, syzbot will apply it before testing. 341 `, extBugID1, reproCLink, reproSyzLink, crashLogLink, kernelConfigLink)) 342 c.checkURLContents(reproCLink, cRepro) 343 c.checkURLContents(reproSyzLink, syzRepro) 344 c.checkURLContents(crashLogLink, crash.Log) 345 c.checkURLContents(kernelConfigLink, build2.KernelConfig) 346 } 347 348 // Send an invalid command. 349 incoming4 := fmt.Sprintf(`Sender: syzkaller@googlegroups.com 350 Date: Tue, 15 Aug 2017 14:59:00 -0700 351 Message-ID: <abcdef> 352 Subject: title1 353 From: foo@bar.com 354 To: %v 355 Content-Type: text/plain 356 357 #syz bad-command 358 `, sender1) 359 360 _, err = c.POST("/_ah/mail/", incoming4) 361 c.expectOK(err) 362 363 { 364 msg := c.pollEmailBug() 365 c.expectEQ(msg.To, []string{"foo@bar.com"}) 366 c.expectEQ(msg.Subject, "Re: title1") 367 c.expectEQ(msg.Headers["In-Reply-To"], []string{"<abcdef>"}) 368 if !strings.Contains(msg.Body, `> #syz bad-command 369 370 unknown command "bad-command" 371 `) { 372 t.Fatal("no unknown command reply for bad command") 373 } 374 } 375 376 // Now mark the bug as fixed. 377 c.incomingEmail(sender1, "#syz fix: some: commit title", 378 EmailOptCC([]string{"bugs@syzkaller.com", "default@maintainers.com"}), 379 EmailOptSubject("fix bug title")) 380 381 // Check that the commit is now passed to builders. 382 builderPollResp, _ := c.client2.BuilderPoll(build.Manager) 383 c.expectEQ(len(builderPollResp.PendingCommits), 1) 384 c.expectEQ(builderPollResp.PendingCommits[0], "some: commit title") 385 386 build3 := testBuild(3) 387 build3.Manager = build.Manager 388 build3.Commits = []string{"some: commit title"} 389 c.client2.UploadBuild(build3) 390 391 build4 := testBuild(4) 392 build4.Manager = build2.Manager 393 build4.Commits = []string{"some: commit title"} 394 c.client2.UploadBuild(build4) 395 396 // New crash must produce new bug in the first reporting. 397 c.client2.ReportCrash(crash) 398 { 399 msg := c.pollEmailBug() 400 c.expectEQ(msg.Subject, crash.Title+" (2)") 401 c.expectNE(msg.Sender, sender0) 402 } 403 } 404 405 // Bug must not be mailed to maintainers if maintainers list is empty. 406 func TestEmailNoMaintainers(t *testing.T) { 407 c := NewCtx(t) 408 defer c.Close() 409 410 build := testBuild(1) 411 c.client2.UploadBuild(build) 412 413 crash := testCrash(build, 1) 414 c.client2.ReportCrash(crash) 415 416 sender := c.pollEmailBug().Sender 417 418 incoming1 := fmt.Sprintf(`Sender: syzkaller@googlegroups.com 419 Date: Tue, 15 Aug 2017 14:59:00 -0700 420 Message-ID: <1234> 421 Subject: crash1 422 From: %v 423 To: foo@bar.com 424 Content-Type: text/plain 425 426 #syz upstream 427 `, sender) 428 _, err := c.POST("/_ah/mail/", incoming1) 429 c.expectOK(err) 430 } 431 432 // Basic dup scenario: mark one bug as dup of another. 433 func TestEmailDup(t *testing.T) { 434 c := NewCtx(t) 435 defer c.Close() 436 437 build := testBuild(1) 438 c.client2.UploadBuild(build) 439 440 crash1 := testCrash(build, 1) 441 crash1.Title = "BUG: slightly more elaborate title" 442 c.client2.ReportCrash(crash1) 443 444 crash2 := testCrash(build, 2) 445 crash2.Title = "KASAN: another title" 446 c.client2.ReportCrash(crash2) 447 448 msg1 := c.pollEmailBug() 449 msg2 := c.pollEmailBug() 450 451 // Dup crash2 to crash1. 452 c.incomingEmail(msg2.Sender, "#syz dup: BUG: slightly more elaborate title") 453 c.expectNoEmail() 454 455 // Second crash happens again. 456 crash2.ReproC = []byte("int main() {}") 457 c.client2.ReportCrash(crash2) 458 c.expectNoEmail() 459 460 // Now close the original bug, and check that new bugs for dup are now created. 461 c.incomingEmail(msg1.Sender, "#syz invalid") 462 463 // "uncc" command must not trugger error reply even for closed bug. 464 c.incomingEmail(msg1.Sender, "#syz uncc", EmailOptCC(nil)) 465 c.expectNoEmail() 466 467 // New crash must produce new bug in the first reporting. 468 c.client2.ReportCrash(crash2) 469 { 470 msg := c.pollEmailBug() 471 c.expectEQ(msg.Subject, crash2.Title+" (2)") 472 } 473 } 474 475 func TestEmailDup2(t *testing.T) { 476 for i := 0; i < 4; i++ { 477 i := i 478 t.Run(fmt.Sprint(i), func(t *testing.T) { 479 c := NewCtx(t) 480 defer c.Close() 481 build := testBuild(1) 482 c.client2.UploadBuild(build) 483 484 crash1 := testCrash(build, 1) 485 crash1.Title = "BUG: something bad" 486 c.client2.ReportCrash(crash1) 487 msg1 := c.pollEmailBug() 488 c.incomingEmail(msg1.Sender, "#syz upstream") 489 msg1 = c.pollEmailBug() 490 c.expectEQ(msg1.Subject, "[syzbot] BUG: something bad") 491 492 crash2 := testCrash(build, 2) 493 crash2.Title = "KASAN: another bad thing" 494 c.client2.ReportCrash(crash2) 495 msg2 := c.pollEmailBug() 496 c.incomingEmail(msg2.Sender, "#syz upstream") 497 msg2 = c.pollEmailBug() 498 c.expectEQ(msg2.Subject, "[syzbot] KASAN: another bad thing") 499 500 cc := EmailOptCC([]string{"bugs@syzkaller.com", "default@maintainers.com"}) 501 switch i { 502 case 0: 503 c.incomingEmail(msg2.Sender, "#syz dup: BUG: something bad", cc) 504 case 1: 505 c.incomingEmail(msg2.Sender, "#syz dup: [syzbot] BUG: something bad", cc) 506 case 2: 507 c.incomingEmail(msg2.Sender, "#syz dup: [syzbot] [subsystemA?] BUG: something bad", cc) 508 default: 509 c.incomingEmail(msg2.Sender, "#syz dup: syzbot: BUG: something bad", cc) 510 reply := c.pollEmailBug() 511 c.expectTrue(strings.Contains(reply.Body, "can't find the dup bug")) 512 } 513 }) 514 } 515 } 516 517 func TestEmailUndup(t *testing.T) { 518 c := NewCtx(t) 519 defer c.Close() 520 521 build := testBuild(1) 522 c.client2.UploadBuild(build) 523 524 crash1 := testCrash(build, 1) 525 crash1.Title = "BUG: slightly more elaborate title" 526 c.client2.ReportCrash(crash1) 527 528 crash2 := testCrash(build, 2) 529 crash1.Title = "KASAN: another title" 530 c.client2.ReportCrash(crash2) 531 532 msg1 := c.pollEmailBug() 533 msg2 := c.pollEmailBug() 534 535 // Dup crash2 to crash1. 536 c.incomingEmail(msg2.Sender, "#syz dup BUG: slightly more elaborate title") 537 c.expectNoEmail() 538 539 // Undup crash2. 540 c.incomingEmail(msg2.Sender, "#syz undup") 541 c.expectNoEmail() 542 543 // Now close the original bug, and check that new crashes for the dup does not create bugs. 544 c.incomingEmail(msg1.Sender, "#syz invalid") 545 c.client2.ReportCrash(crash2) 546 c.expectNoEmail() 547 } 548 549 func TestEmailCrossReportingDup(t *testing.T) { 550 c := NewCtx(t) 551 defer c.Close() 552 553 build := testBuild(1) 554 c.client2.UploadBuild(build) 555 556 tests := []struct { 557 bug int 558 dup int 559 result bool 560 }{ 561 {0, 0, true}, 562 {0, 1, false}, 563 {0, 2, false}, 564 {1, 0, false}, 565 {1, 1, true}, 566 {1, 2, true}, 567 {2, 0, false}, 568 {2, 1, false}, 569 {2, 2, true}, 570 } 571 for i, test := range tests { 572 t.Logf("duping %v->%v, expect %v", test.bug, test.dup, test.result) 573 c.advanceTime(24 * time.Hour) // to not hit email limit per day 574 crash1 := testCrash(build, 1) 575 crash1.Title = fmt.Sprintf("bug_%v", i) 576 c.client2.ReportCrash(crash1) 577 bugSender := c.pollEmailBug().Sender 578 cc := EmailOptCC([]string{"default@maintainers.com", "test@syzkaller.com", 579 "bugs@syzkaller.com", "default2@maintainers.com", "bugs2@syzkaller.com"}) 580 for j := 0; j < test.bug; j++ { 581 c.incomingEmail(bugSender, "#syz upstream", cc) 582 bugSender = c.pollEmailBug().Sender 583 } 584 585 crash2 := testCrash(build, 2) 586 crash2.Title = fmt.Sprintf("dup_%v", i) 587 c.client2.ReportCrash(crash2) 588 dupSender := c.pollEmailBug().Sender 589 for j := 0; j < test.dup; j++ { 590 c.incomingEmail(dupSender, "#syz upstream", cc) 591 dupSender = c.pollEmailBug().Sender 592 } 593 594 c.incomingEmail(bugSender, "#syz dup: "+crash2.Title, cc) 595 if test.result { 596 c.expectNoEmail() 597 } else { 598 msg := c.pollEmailBug() 599 if !strings.Contains(msg.Body, "> #syz dup:") || 600 !strings.Contains(msg.Body, "Can't dup bug to a bug in different reporting") { 601 c.t.Fatalf("bad reply body:\n%v", msg.Body) 602 } 603 } 604 } 605 } 606 607 func TestEmailErrors(t *testing.T) { 608 c := NewCtx(t) 609 defer c.Close() 610 611 // No reply for email without bug hash and no commands. 612 c.incomingEmail("syzbot@testapp.appspotmail.com", "Investment Proposal") 613 c.expectNoEmail() 614 615 // If email contains a command we need to reply. 616 c.incomingEmail("syzbot@testapp.appspotmail.com", "#syz invalid") 617 reply := c.pollEmailBug() 618 c.expectEQ(reply.To, []string{"default@sender.com"}) 619 c.expectEQ(reply.Body, `> #syz invalid 620 621 I see the command but can't find the corresponding bug. 622 Please resend the email to syzbot+HASH@testapp.appspotmail.com address 623 that is the sender of the bug report (also present in the Reported-by tag). 624 625 `) 626 627 c.incomingEmail("syzbot+123@testapp.appspotmail.com", "#syz invalid") 628 reply = c.pollEmailBug() 629 c.expectEQ(reply.Body, `> #syz invalid 630 631 I see the command but can't find the corresponding bug. 632 The email is sent to syzbot+HASH@testapp.appspotmail.com address 633 but the HASH does not correspond to any known bug. 634 Please double check the address. 635 636 `) 637 } 638 639 func TestEmailFailedBuild(t *testing.T) { 640 c := NewCtx(t) 641 defer c.Close() 642 643 build := testBuild(1) 644 c.client2.UploadBuild(build) 645 646 failedBuild := testBuild(10) 647 failedBuild.KernelRepo = testConfig.Namespaces["test2"].Repos[0].URL 648 failedBuild.KernelBranch = testConfig.Namespaces["test2"].Repos[0].Branch 649 failedBuild.KernelCommit = "kern2" 650 failedBuild.KernelCommitTitle = "failed build 1" 651 failedBuild.SyzkallerCommit = "syz2" 652 buildErrorReq := &dashapi.BuildErrorReq{ 653 Build: *failedBuild, 654 Crash: dashapi.Crash{ 655 Title: "failed build 1", 656 Report: []byte("report line 1\nreport line 2\n"), 657 Log: []byte("log line 1\nlog line 2\n"), 658 Maintainers: []string{"maintainer@crash"}, 659 }, 660 } 661 c.expectOK(c.client2.ReportBuildError(buildErrorReq)) 662 663 msg := c.pollEmailBug() 664 sender, extBugID, err := email.RemoveAddrContext(msg.Sender) 665 c.expectOK(err) 666 _, dbCrash, dbBuild := c.loadBug(extBugID) 667 crashLogLink := externalLink(c.ctx, textCrashLog, dbCrash.Log) 668 kernelConfigLink := externalLink(c.ctx, textKernelConfig, dbBuild.KernelConfig) 669 c.expectEQ(sender, fromAddr(c.ctx)) 670 c.expectEQ(msg.To, []string{ 671 "always@cc.me", 672 "test@syzkaller.com", 673 }) 674 c.expectEQ(msg.Subject, buildErrorReq.Crash.Title) 675 c.expectEQ(len(msg.Attachments), 0) 676 c.expectEQ(msg.Body, fmt.Sprintf(`Hello, 677 678 syzbot found the following issue on: 679 680 HEAD commit: kern2 failed build 1 681 git tree: repo10alias 682 console output: %[2]v 683 kernel config: %[3]v 684 dashboard link: https://testapp.appspot.com/bug?extid=%[1]v 685 compiler: compiler10 686 CC: [maintainer@crash maintainers@repo10.org bugs@repo10.org build-maintainers@repo10.org] 687 688 IMPORTANT: if you fix the issue, please add the following tag to the commit: 689 Reported-by: syzbot+%[1]v@testapp.appspotmail.com 690 691 report line 1 692 report line 2 693 694 695 --- 696 This report is generated by a bot. It may contain errors. 697 See https://goo.gl/tpsmEJ for more information about syzbot. 698 syzbot engineers can be reached at syzkaller@googlegroups.com. 699 700 syzbot will keep track of this issue. See: 701 https://goo.gl/tpsmEJ#status for how to communicate with syzbot. 702 703 If the report is already addressed, let syzbot know by replying with: 704 #syz fix: exact-commit-title 705 706 If you want to overwrite report's subsystems, reply with: 707 #syz set subsystems: new-subsystem 708 (See the list of subsystem names on the web dashboard) 709 710 If the report is a duplicate of another one, reply with: 711 #syz dup: exact-subject-of-another-report 712 713 If you want to undo deduplication, reply with: 714 #syz undup`, 715 extBugID, crashLogLink, kernelConfigLink)) 716 } 717 718 // Test for unfix command which should unmark a bug as fixed by any commits. 719 func TestEmailUnfix(t *testing.T) { 720 c := NewCtx(t) 721 defer c.Close() 722 723 build := testBuild(1) 724 c.client2.UploadBuild(build) 725 726 crash := testCrash(build, 1) 727 c.client2.ReportCrash(crash) 728 729 msg := c.pollEmailBug() 730 731 c.incomingEmail(msg.Sender, "#syz fix: some commit") 732 c.expectNoEmail() 733 c.incomingEmail(msg.Sender, "#syz unfix") 734 c.expectNoEmail() 735 736 build2 := testBuild(2) 737 build2.Manager = build.Manager 738 build2.Commits = []string{"some commit"} 739 c.client2.UploadBuild(build2) 740 741 // The bug should be still unfixed, since we unmarked it. 742 c.client2.ReportCrash(crash) 743 c.expectNoEmail() 744 } 745 746 func TestEmailManagerCC(t *testing.T) { 747 c := NewCtx(t) 748 defer c.Close() 749 750 // Test that we add manager CC. 751 build1 := testBuild(1) 752 build1.Manager = specialCCManager 753 c.client2.UploadBuild(build1) 754 755 crash := testCrash(build1, 1) 756 c.client2.ReportCrash(crash) 757 758 msg := c.pollEmailBug() 759 c.expectEQ(msg.To, []string{ 760 "always@manager.org", 761 "test@syzkaller.com", 762 }) 763 764 // Test that we add manager maintainers. 765 c.incomingEmail(msg.Sender, "#syz upstream") 766 msg = c.pollEmailBug() 767 c.expectEQ(msg.To, []string{ 768 "always@manager.org", 769 "bugs@syzkaller.com", 770 "default@maintainers.com", 771 "maintainers@manager.org", 772 }) 773 774 // Test that we add manager build maintainers. 775 build2 := testBuild(2) 776 build2.Manager = specialCCManager 777 buildErrorReq := &dashapi.BuildErrorReq{ 778 Build: *build2, 779 Crash: dashapi.Crash{ 780 Title: "failed build 1", 781 Report: []byte("report\n"), 782 Log: []byte("log\n"), 783 }, 784 } 785 c.expectOK(c.client2.ReportBuildError(buildErrorReq)) 786 msg = c.pollEmailBug() 787 c.expectEQ(msg.To, []string{ 788 "always@manager.org", 789 "test@syzkaller.com", 790 }) 791 792 c.incomingEmail(msg.Sender, "#syz upstream") 793 msg = c.pollEmailBug() 794 c.expectEQ(msg.To, []string{ 795 "always@manager.org", 796 "bugs@syzkaller.com", 797 "build-maintainers@manager.org", 798 "default@maintainers.com", 799 "maintainers@manager.org", 800 }) 801 802 // Test that we don't add manager CC when the crash happened on 1+ managers. 803 build3 := testBuild(3) 804 build1.Manager = specialCCManager 805 c.client2.UploadBuild(build3) 806 crash = testCrash(build3, 2) 807 c.client2.ReportCrash(crash) 808 809 build4 := testBuild(4) 810 c.client2.UploadBuild(build4) 811 crash = testCrash(build4, 2) 812 c.client2.ReportCrash(crash) 813 814 msg = c.pollEmailBug() 815 c.expectEQ(msg.To, []string{ 816 "test@syzkaller.com", 817 }) 818 819 c.incomingEmail(msg.Sender, "#syz upstream") 820 msg = c.pollEmailBug() 821 c.expectEQ(msg.To, []string{ 822 "bugs@syzkaller.com", 823 "default@maintainers.com", 824 }) 825 } 826 827 func TestStraceReport(t *testing.T) { 828 c := NewCtx(t) 829 defer c.Close() 830 831 build := testBuild(1) 832 c.client2.UploadBuild(build) 833 834 crash := testCrash(build, 1) 835 crash.Flags = dashapi.CrashUnderStrace 836 crash.Maintainers = []string{`"Foo Bar" <foo@bar.com>`, `bar@foo.com`, `idont@want.EMAILS`} 837 c.client2.ReportCrash(crash) 838 839 // Report the crash over email and check all fields. 840 msg := c.pollEmailBug() 841 _, extBugID, err := email.RemoveAddrContext(msg.Sender) 842 c.expectOK(err) 843 _, dbCrash, dbBuild := c.loadBug(extBugID) 844 crashLogLink := externalLink(c.ctx, textCrashLog, dbCrash.Log) 845 kernelConfigLink := externalLink(c.ctx, textKernelConfig, dbBuild.KernelConfig) 846 c.expectEQ(msg.Body, fmt.Sprintf(`Hello, 847 848 syzbot found the following issue on: 849 850 HEAD commit: 111111111111 kernel_commit_title1 851 git tree: repo1 branch1 852 console+strace: %[2]v 853 kernel config: %[3]v 854 dashboard link: https://testapp.appspot.com/bug?extid=%[1]v 855 compiler: compiler1 856 CC: [bar@foo.com foo@bar.com idont@want.EMAILS] 857 858 Unfortunately, I don't have any reproducer for this issue yet. 859 860 IMPORTANT: if you fix the issue, please add the following tag to the commit: 861 Reported-by: syzbot+%[1]v@testapp.appspotmail.com 862 863 report1 864 865 --- 866 This report is generated by a bot. It may contain errors. 867 See https://goo.gl/tpsmEJ for more information about syzbot. 868 syzbot engineers can be reached at syzkaller@googlegroups.com. 869 870 syzbot will keep track of this issue. See: 871 https://goo.gl/tpsmEJ#status for how to communicate with syzbot. 872 873 If the report is already addressed, let syzbot know by replying with: 874 #syz fix: exact-commit-title 875 876 If you want to overwrite report's subsystems, reply with: 877 #syz set subsystems: new-subsystem 878 (See the list of subsystem names on the web dashboard) 879 880 If the report is a duplicate of another one, reply with: 881 #syz dup: exact-subject-of-another-report 882 883 If you want to undo deduplication, reply with: 884 #syz undup`, 885 extBugID, crashLogLink, kernelConfigLink)) 886 c.checkURLContents(crashLogLink, crash.Log) 887 } 888 889 func TestSubjectTitleParser(t *testing.T) { 890 tests := []struct { 891 inSubject string 892 outTitle string 893 outSeq int64 894 }{ 895 { 896 inSubject: "Re: kernel BUG in blk_mq_dispatch_rq_list (4)", 897 outTitle: "kernel BUG in blk_mq_dispatch_rq_list", 898 outSeq: 3, 899 }, 900 { 901 inSubject: "Re: [syzbot] kernel BUG in blk_mq_dispatch_rq_list (4)", 902 outTitle: "kernel BUG in blk_mq_dispatch_rq_list", 903 outSeq: 3, 904 }, 905 { 906 // Make sure we always take the (number) at the end. 907 inSubject: "Re: kernel BUG in blk_mq_dispatch_rq_list(6) (4)", 908 outTitle: "kernel BUG in blk_mq_dispatch_rq_list(6)", 909 outSeq: 3, 910 }, 911 { 912 inSubject: "RE: kernel BUG in blk_mq_dispatch_rq_list", 913 outTitle: "kernel BUG in blk_mq_dispatch_rq_list", 914 outSeq: 0, 915 }, 916 { 917 // Make sure we trim the title. 918 inSubject: "RE: kernel BUG in blk_mq_dispatch_rq_list ", 919 outTitle: "kernel BUG in blk_mq_dispatch_rq_list", 920 outSeq: 0, 921 }, 922 { 923 inSubject: "Re: ", 924 outTitle: "", 925 outSeq: 0, 926 }, 927 { 928 inSubject: "Re: [syzbot]", 929 outTitle: "", 930 outSeq: 0, 931 }, 932 { 933 inSubject: "Re: [syzbot] [subsystemA?]", 934 outTitle: "", 935 outSeq: 0, 936 }, 937 { 938 // Make sure we delete filesystem tags. 939 inSubject: "Re: [syzbot] [ntfs3?] [ext4?] kernel BUG in blk_mq_dispatch_rq_list (4)", 940 outTitle: "kernel BUG in blk_mq_dispatch_rq_list", 941 outSeq: 3, 942 }, 943 } 944 945 p := makeSubjectTitleParser(context.Background()) 946 for _, test := range tests { 947 title, seq, err := p.parseTitle(test.inSubject) 948 if test.outTitle == "" { 949 if err == nil { 950 t.Fatalf("subj: %q, expected error, got none (%q)", test.inSubject, title) 951 } 952 } else if title != test.outTitle { 953 t.Fatalf("subj: %q, expected title=%q, got %q", test.inSubject, test.outTitle, title) 954 } else if seq != test.outSeq { 955 t.Fatalf("subj: %q, expected seq=%q, got %q", test.inSubject, test.outSeq, seq) 956 } 957 } 958 } 959 960 func TestBugFromSubjectInference(t *testing.T) { 961 c := NewCtx(t) 962 defer c.Close() 963 964 client := c.makeClient(clientPublicEmail, keyPublicEmail, true) 965 client2 := c.makeClient(clientPublicEmail2, keyPublicEmail2, true) 966 967 build := testBuild(1) 968 client.UploadBuild(build) 969 970 build2 := testBuild(2) 971 client2.UploadBuild(build2) 972 973 const crashTitle = "WARNING in corrupted" 974 upstreamCrash := func(client *apiClient, build *dashapi.Build, title string) string { 975 // Upload some garbage crashes. 976 crash := testCrash(build, 1) 977 crash.Title = title 978 crash.Log = []byte(fmt.Sprintf("log%v", title)) 979 crash.Maintainers = []string{"maintainer@kernel.org"} 980 client.ReportCrash(crash) 981 982 sender := c.pollEmailBug().Sender 983 c.incomingEmail(sender, "#syz upstream\n") 984 985 return c.pollEmailBug().Sender 986 } 987 988 upstreamCrash(client, build, "unrelated crash") 989 origSender := upstreamCrash(client, build, crashTitle) 990 upstreamCrash(client, build, "unrelated crash 2") 991 992 mailingList := "<" + c.config().Namespaces["access-public-email"].Reporting[0].Config.(*EmailConfig).Email + ">" 993 994 // First try to ping some non-existing bug. 995 subject := "Re: unknown-bug" 996 c.incomingEmail("bugs@syzkaller.com", 997 syzTestGitBranchSamplePatch, 998 EmailOptOrigFrom("test@requester.com"), 999 EmailOptFrom(mailingList), EmailOptSubject(subject), 1000 ) 1001 syzbotReply := c.pollEmailBug() 1002 c.expectNE(syzbotReply.Sender, origSender) 1003 c.expectEQ(strings.Contains(syzbotReply.Body, "can't find the corresponding bug"), true) 1004 1005 // Now try to test the exiting bug, but with the wrong mailing list. 1006 subject = "Re: " + crashTitle 1007 c.incomingEmail("bugs@syzkaller.com", 1008 syzTestGitBranchSamplePatch, 1009 EmailOptOrigFrom("test@requester.com"), 1010 EmailOptFrom("<unknown-list@syzkaller.com>"), EmailOptSubject(subject), 1011 ) 1012 body := c.pollEmailBug().Body 1013 c.expectEQ(strings.Contains(body, "can't find the corresponding bug"), true) 1014 1015 // Now try to test the exiting bug with the proper mailing list. 1016 c.incomingEmail("bugs@syzkaller.com", 1017 syzTestGitBranchSamplePatch, 1018 EmailOptFrom(mailingList), EmailOptOrigFrom("test@requester.com"), 1019 EmailOptSubject(subject), 1020 ) 1021 syzbotReply = c.pollEmailBug() 1022 c.expectEQ(syzbotReply.Sender, origSender) 1023 c.expectEQ(strings.Contains(syzbotReply.Body, "This crash does not have a reproducer"), true) 1024 1025 // Test that a different type of email headers is also parsed fine. 1026 c.incomingEmail("bugs@syzkaller.com", 1027 syzTestGitBranchSamplePatch, 1028 EmailOptSender(mailingList), EmailOptFrom("test@requester.com"), 1029 EmailOptSubject(subject), 1030 ) 1031 body = c.pollEmailBug().Body 1032 c.expectEQ(strings.Contains(body, "This crash does not have a reproducer"), true) 1033 1034 // Upstream a same-titled bug in another namespace. 1035 upstreamCrash(client2, build2, crashTitle) 1036 1037 // Ensure that the inference fails with the proper title. 1038 c.incomingEmail("bugs@syzkaller.com", 1039 syzTestGitBranchSamplePatch, 1040 EmailOptSender(mailingList), EmailOptFrom("test@requester.com"), 1041 EmailOptSubject(subject), 1042 ) 1043 body = c.pollEmailBug().Body 1044 c.expectEQ(strings.Contains(body, "Several bugs with the exact same title"), true) 1045 1046 // Close the existing bug. 1047 c.incomingEmail("bugs@syzkaller.com", "#syz invalid", 1048 EmailOptFrom("test@requester.com"), EmailOptSubject(subject), 1049 EmailOptCC([]string{mailingList, origSender}), 1050 ) 1051 c.expectNoEmail() 1052 1053 // Create the (2) of the bug. 1054 upstreamCrash(client, build, crashTitle) 1055 1056 // Make sure syzbot can understand the (2) version. 1057 subject = "Re: " + crashTitle + " (2)" 1058 c.incomingEmail("bugs@syzkaller.com", 1059 syzTestGitBranchSamplePatch, 1060 EmailOptFrom(mailingList), EmailOptOrigFrom("<test@requester.com>"), 1061 EmailOptSubject(subject), 1062 ) 1063 email := c.pollEmailBug() 1064 c.expectEQ(email.To, []string{"test@requester.com"}) 1065 c.expectEQ(strings.Contains(email.Body, "This crash does not have a reproducer"), true) 1066 } 1067 1068 // nolint: funlen 1069 func TestEmailLinks(t *testing.T) { 1070 c := NewCtx(t) 1071 defer c.Close() 1072 1073 build := testBuild(1) 1074 c.client2.UploadBuild(build) 1075 1076 crash := testCrash(build, 1) 1077 crash.Maintainers = []string{`"Foo Bar" <foo@bar.com>`} 1078 c.client2.ReportCrash(crash) 1079 1080 // Report the crash over email. 1081 msg := c.pollEmailBug() 1082 1083 // Emulate receive of the report from a mailing list. 1084 // This should update the bug with the link/Message-ID. 1085 // nolint: lll 1086 incoming1 := fmt.Sprintf(`Sender: syzkaller@googlegroups.com 1087 Date: Tue, 15 Aug 2017 14:59:00 -0700 1088 Message-ID: <1234> 1089 Subject: crash1 1090 From: %v 1091 To: foo@bar.com 1092 Content-Type: text/plain 1093 1094 Hello 1095 1096 syzbot will keep track of this issue. 1097 If you forgot to add the Reported-by tag, once the fix for this bug is merged 1098 into any tree, please reply to this email with: 1099 #syz fix: exact-commit-title 1100 To mark this as a duplicate of another syzbot report, please reply with: 1101 #syz dup: exact-subject-of-another-report 1102 If it's a one-off invalid bug report, please reply with: 1103 #syz invalid 1104 1105 -- 1106 You received this message because you are subscribed to the Google Groups "syzkaller" group. 1107 To unsubscribe from this group and stop receiving emails from it, send an email to syzkaller+unsubscribe@googlegroups.com. 1108 To post to this group, send email to syzkaller@googlegroups.com. 1109 To view this discussion on the web visit https://groups.google.com/d/msgid/syzkaller/1234@google.com. 1110 For more options, visit https://groups.google.com/d/optout. 1111 `, msg.Sender) 1112 1113 _, err := c.POST("/_ah/mail/", incoming1) 1114 c.expectOK(err) 1115 1116 _, extBugID, err := email.RemoveAddrContext(msg.Sender) 1117 c.expectOK(err) 1118 1119 // Make sure Link is set for the last Reporting. 1120 dbBug, _, _ := c.loadBug(extBugID) 1121 reporting := lastReportedReporting(dbBug) 1122 c.expectNE(reporting.Link, "") 1123 } 1124 1125 func TestEmailPatchTestingAccess(t *testing.T) { 1126 c := NewCtx(t) 1127 defer c.Close() 1128 1129 client := c.client2 1130 1131 build := testBuild(1) 1132 client.UploadBuild(build) 1133 1134 crash := testCrash(build, 1) 1135 client.ReportCrash(crash) 1136 1137 sender := c.pollEmailBug().Sender 1138 c.incomingEmail(sender, 1139 syzTestGitBranchSamplePatch, 1140 EmailOptFrom("user@kernel.org"), EmailOptSubject("Re: "+crash.Title), 1141 ) 1142 1143 // We expect syzbot to just ignore this patch testing request. 1144 c.expectNoEmail() 1145 1146 // The patch test job should also not be created. 1147 pollResp := client.pollJobs(build.Manager) 1148 c.expectEQ(pollResp.ID, "") 1149 } 1150 1151 func TestEmailSetInvalidSubsystems(t *testing.T) { 1152 c := NewCtx(t) 1153 defer c.Close() 1154 1155 client := c.makeClient(clientPublicEmail, keyPublicEmail, true) 1156 mailingList := c.config().Namespaces["access-public-email"].Reporting[0].Config.(*EmailConfig).Email 1157 1158 build := testBuild(1) 1159 client.UploadBuild(build) 1160 1161 crash := testCrash(build, 1) 1162 client.ReportCrash(crash) 1163 c.incomingEmail(c.pollEmailBug().Sender, "#syz upstream\n") 1164 1165 sender := c.pollEmailBug().Sender 1166 1167 // Invalid subsystem name. 1168 c.incomingEmail(sender, "#syz set subsystems: non-existent", 1169 EmailOptFrom("test@requester.com"), EmailOptCC([]string{mailingList})) 1170 c.expectEQ(c.pollEmailBug().Body, `> #syz set subsystems: non-existent 1171 1172 The specified label value is incorrect. 1173 "non-existent" is not among the allowed values. 1174 Please use one of the supported label values. 1175 1176 The following labels are suported: 1177 missing-backport, no-reminders, prio: {low, normal, high}, subsystems: {.. see below ..} 1178 The list of subsystems: https://testapp.appspot.com/access-public-email/subsystems?all=true 1179 1180 `) 1181 } 1182 1183 func TestEmailSetSubsystems(t *testing.T) { 1184 c := NewCtx(t) 1185 defer c.Close() 1186 1187 client := c.makeClient(clientPublicEmail, keyPublicEmail, true) 1188 mailingList := c.config().Namespaces["access-public-email"].Reporting[0].Config.(*EmailConfig).Email 1189 1190 build := testBuild(1) 1191 client.UploadBuild(build) 1192 1193 crash := testCrash(build, 1) 1194 client.ReportCrash(crash) 1195 c.incomingEmail(c.pollEmailBug().Sender, "#syz upstream\n") 1196 1197 sender := c.pollEmailBug().Sender 1198 _, extBugID, err := email.RemoveAddrContext(sender) 1199 c.expectOK(err) 1200 1201 // At the beginning, there are no subsystems. 1202 expectLabels(t, client, extBugID) 1203 1204 // Set one subsystem. 1205 c.incomingEmail(sender, "#syz set subsystems: subsystemA\n", 1206 EmailOptFrom("test@requester.com"), EmailOptCC([]string{mailingList})) 1207 expectLabels(t, client, extBugID, "subsystems:subsystemA") 1208 1209 // Set two subsystems. 1210 c.incomingEmail(sender, "#syz set subsystems: subsystemA, subsystemB\n", 1211 EmailOptFrom("test@requester.com"), EmailOptCC([]string{mailingList})) 1212 expectLabels(t, client, extBugID, "subsystems:subsystemA", "subsystems:subsystemB") 1213 } 1214 1215 func TestEmailBugLabels(t *testing.T) { 1216 c := NewCtx(t) 1217 defer c.Close() 1218 1219 client := c.makeClient(clientPublicEmail, keyPublicEmail, true) 1220 mailingList := c.config().Namespaces["access-public-email"].Reporting[0].Config.(*EmailConfig).Email 1221 1222 build := testBuild(1) 1223 client.UploadBuild(build) 1224 1225 crash := testCrash(build, 1) 1226 client.ReportCrash(crash) 1227 1228 sender := c.pollEmailBug().Sender 1229 _, extBugID, err := email.RemoveAddrContext(sender) 1230 c.expectOK(err) 1231 1232 // At the beginning, there are no tags. 1233 expectLabels(t, client, extBugID) 1234 1235 // Set a tag. 1236 c.incomingEmail(sender, "#syz set prio: low\n", 1237 EmailOptFrom("test@requester.com"), EmailOptCC([]string{mailingList})) 1238 expectLabels(t, client, extBugID, "prio:low") 1239 1240 // Notice that medium prio supercedes low prio since they are of the oneOf type. 1241 c.incomingEmail(sender, "#syz set prio: high\n", 1242 EmailOptFrom("test@requester.com"), EmailOptCC([]string{mailingList})) 1243 expectLabels(t, client, extBugID, "prio:high") 1244 1245 // Also set a flag label. 1246 c.incomingEmail(sender, "#syz set no-reminders\n", 1247 EmailOptFrom("test@requester.com"), EmailOptCC([]string{mailingList})) 1248 expectLabels(t, client, extBugID, "prio:high", "no-reminders") 1249 1250 // Remove a tag. 1251 c.incomingEmail(sender, "#syz unset prio\n", 1252 EmailOptFrom("test@requester.com"), EmailOptCC([]string{mailingList})) 1253 expectLabels(t, client, extBugID, "no-reminders") 1254 1255 // Remove another tag. 1256 c.incomingEmail(sender, "#syz unset no-reminders\n", 1257 EmailOptFrom("test@requester.com"), EmailOptCC([]string{mailingList})) 1258 expectLabels(t, client, extBugID) 1259 } 1260 1261 func TestInvalidEmailBugLabels(t *testing.T) { 1262 c := NewCtx(t) 1263 defer c.Close() 1264 1265 client := c.makeClient(clientPublicEmail, keyPublicEmail, true) 1266 mailingList := c.config().Namespaces["access-public-email"].Reporting[0].Config.(*EmailConfig).Email 1267 1268 build := testBuild(1) 1269 client.UploadBuild(build) 1270 1271 crash := testCrash(build, 1) 1272 client.ReportCrash(crash) 1273 c.incomingEmail(c.pollEmailBug().Sender, "#syz upstream\n") 1274 1275 sender := c.pollEmailBug().Sender 1276 1277 // Non-existing label. 1278 c.incomingEmail(sender, "#syz set label: tag", 1279 EmailOptFrom("test@requester.com"), EmailOptCC([]string{mailingList})) 1280 body := c.pollEmailBug().Body 1281 c.expectEQ(body, `> #syz set label: tag 1282 1283 The specified label "label" is unknown. 1284 Please use one of the supported labels. 1285 1286 The following labels are suported: 1287 missing-backport, no-reminders, prio: {low, normal, high}, subsystems: {.. see below ..} 1288 The list of subsystems: https://testapp.appspot.com/access-public-email/subsystems?all=true 1289 1290 `) 1291 1292 // Existing label, wrong value. 1293 c.incomingEmail(sender, "#syz set prio: unknown\n", 1294 EmailOptFrom("test@requester.com"), EmailOptCC([]string{mailingList})) 1295 c.expectEQ(strings.Contains(c.pollEmailBug().Body, 1296 `The specified label value is incorrect. 1297 "unknown" is not among the allowed values`), true) 1298 1299 // Existing label, too many values. 1300 c.incomingEmail(sender, "#syz set prio: low, high\n", 1301 EmailOptFrom("test@requester.com"), EmailOptCC([]string{mailingList})) 1302 c.expectEQ(strings.Contains(c.pollEmailBug().Body, 1303 `The specified label value is incorrect. 1304 You must specify only one of the allowed values.`), true) 1305 1306 // Removing a non-existing label. 1307 c.incomingEmail(sender, "#syz unset tag2\n", 1308 EmailOptFrom("test@requester.com"), EmailOptCC([]string{mailingList})) 1309 syzbotReply := c.pollEmailBug() 1310 c.expectEQ(strings.Contains(syzbotReply.Body, "The following labels did not exist: tag2"), true) 1311 } 1312 1313 func expectLabels(t *testing.T, client *apiClient, extID string, labels ...string) { 1314 t.Helper() 1315 bug, _, _ := client.Ctx.loadBug(extID) 1316 names := []string{} 1317 for _, item := range bug.Labels { 1318 names = append(names, item.String()) 1319 } 1320 assert.ElementsMatch(t, names, labels) 1321 } 1322 1323 var forwardEmailConfig = EmailConfig{ 1324 Email: "test@syzkaller.com", 1325 HandleListEmails: true, 1326 SubjectPrefix: "[syzbot]", 1327 MailMaintainers: true, 1328 DefaultMaintainers: []string{"some@list.com"}, 1329 } 1330 1331 func TestSingleListForward(t *testing.T) { 1332 c := NewCtx(t) 1333 defer c.Close() 1334 1335 client := c.makeClient(clientPublicEmail, keyPublicEmail, true) 1336 c.updateReporting("access-public-email", "access-public-email-reporting1", 1337 func(r Reporting) Reporting { 1338 r.Config = &forwardEmailConfig 1339 return r 1340 }) 1341 1342 build := testBuild(1) 1343 client.UploadBuild(build) 1344 1345 crash := testCrash(build, 1) 1346 client.ReportCrash(crash) 1347 1348 sender := c.pollEmailBug().Sender 1349 1350 c.incomingEmail(sender, "#syz fix: some: commit title", 1351 EmailOptCC([]string{"some@list.com"}), EmailOptSubject("fix bug title")) 1352 1353 forwarded := c.pollEmailBug() 1354 c.expectEQ(forwarded.Subject, "[syzbot] fix bug title") 1355 c.expectEQ(forwarded.Sender, sender) 1356 c.expectEQ(forwarded.To, []string{"test@syzkaller.com"}) 1357 c.expectEQ(len(forwarded.Cc), 0) 1358 c.expectEQ(forwarded.Body, `For archival purposes, forwarding an incoming command email to 1359 test@syzkaller.com. 1360 1361 *** 1362 1363 Subject: fix bug title 1364 Author: default@sender.com 1365 1366 #syz fix: some: commit title 1367 `) 1368 } 1369 1370 func TestTwoListsForward(t *testing.T) { 1371 c := NewCtx(t) 1372 defer c.Close() 1373 1374 client := c.makeClient(clientPublicEmail, keyPublicEmail, true) 1375 c.updateReporting("access-public-email", "access-public-email-reporting1", 1376 func(r Reporting) Reporting { 1377 r.Config = &forwardEmailConfig 1378 return r 1379 }) 1380 1381 build := testBuild(1) 1382 client.UploadBuild(build) 1383 1384 crash := testCrash(build, 1) 1385 client.ReportCrash(crash) 1386 1387 sender := c.pollEmailBug().Sender 1388 1389 c.incomingEmail(sender, "#syz fix: some: commit title", 1390 EmailOptCC(nil), EmailOptSubject("fix bug title")) 1391 1392 forwarded := c.pollEmailBug() 1393 c.expectEQ(forwarded.Subject, "[syzbot] fix bug title") 1394 c.expectEQ(forwarded.Sender, sender) 1395 c.expectEQ(forwarded.To, []string{"some@list.com", "test@syzkaller.com"}) 1396 c.expectEQ(len(forwarded.Cc), 0) 1397 c.expectEQ(forwarded.Body, `For archival purposes, forwarding an incoming command email to 1398 some@list.com, test@syzkaller.com. 1399 1400 *** 1401 1402 Subject: fix bug title 1403 Author: default@sender.com 1404 1405 #syz fix: some: commit title 1406 `) 1407 }