aboutsummaryrefslogtreecommitdiffstats
path: root/pkg
diff options
context:
space:
mode:
authorAleksandr Nogikh <nogikh@google.com>2023-04-17 12:49:12 +0200
committerAleksandr Nogikh <wp32pw@gmail.com>2023-04-27 11:42:09 +0200
commit030e10720439813a9e4a7e4586bdc2bdc781a4c9 (patch)
treefd173364ef340c6c95b7e32f767d7f513c7cfbfd /pkg
parent3187536a2e79fb4a7c5d76ef46e69614696c3497 (diff)
pkg/email: support multiple commands
It's not always convenient that we can receive only one command per email. Update pkg/email parsing code to extract everything which there is. Update reporting_email.go to handle multiple email commands. Set different limits for bug email commands and bug list commands.
Diffstat (limited to 'pkg')
-rw-r--r--pkg/email/lore/parse_test.go8
-rw-r--r--pkg/email/parser.go69
-rw-r--r--pkg/email/parser_test.go359
-rw-r--r--pkg/email/reply.go11
-rw-r--r--pkg/email/reply_test.go54
5 files changed, 323 insertions, 178 deletions
diff --git a/pkg/email/lore/parse_test.go b/pkg/email/lore/parse_test.go
index 84d3d0bdf..13370045c 100644
--- a/pkg/email/lore/parse_test.go
+++ b/pkg/email/lore/parse_test.go
@@ -121,7 +121,6 @@ Bug report`,
Date: time.Date(2017, time.May, 7, 19, 54, 0, 0, zone),
Author: "a@user.com",
Cc: []string{"a@user.com"},
- Command: email.CmdNone,
},
{
MessageID: "<A-Child-1>",
@@ -130,7 +129,6 @@ Bug report`,
Author: "b@user.com",
Cc: []string{"a@user.com", "b@user.com"},
InReplyTo: "<A-Base>",
- Command: email.CmdNone,
},
{
MessageID: "<A-Child-1-1>",
@@ -139,7 +137,6 @@ Bug report`,
Author: "c@user.com",
Cc: []string{"a@user.com", "b@user.com", "c@user.com"},
InReplyTo: "<A-Child-1>",
- Command: email.CmdNone,
},
},
},
@@ -156,7 +153,6 @@ Bug report`,
Date: time.Date(2017, time.May, 7, 19, 57, 0, 0, zone),
Author: "syzbot@bar.com",
OwnEmail: true,
- Command: email.CmdNone,
},
{
MessageID: "<Bug-Reply1>",
@@ -166,7 +162,6 @@ Bug report`,
Author: "c@user.com",
Cc: []string{"c@user.com"},
InReplyTo: "<Bug>",
- Command: email.CmdNone,
},
{
MessageID: "<Bug-Reply2>",
@@ -176,7 +171,6 @@ Bug report`,
Author: "d@user.com",
Cc: []string{"d@user.com"},
InReplyTo: "<Bug>",
- Command: email.CmdNone,
},
},
},
@@ -193,7 +187,6 @@ Bug report`,
Date: time.Date(2017, time.May, 7, 19, 58, 1, 0, zone),
Author: "e@user.com",
Cc: []string{"e@user.com"},
- Command: email.CmdNone,
},
},
},
@@ -211,7 +204,6 @@ Bug report`,
Cc: []string{"person@email.com"},
Subject: "Another bug discussion",
Author: "person@email.com",
- Command: email.CmdNone,
},
},
},
diff --git a/pkg/email/parser.go b/pkg/email/parser.go
index 5b472a57e..152f5e555 100644
--- a/pkg/email/parser.go
+++ b/pkg/email/parser.go
@@ -29,18 +29,21 @@ type Email struct {
Author string
OwnEmail bool
Cc []string
- Body string // text/plain part
- Patch string // attached patch, if any
- Command Command // command to bot
- CommandStr string // string representation of the command
- CommandArgs string // arguments for the command
+ Body string // text/plain part
+ Patch string // attached patch, if any
+ Commands []*SingleCommand
+}
+
+type SingleCommand struct {
+ Command Command
+ Str string // string representation
+ Args string // arguments for the command
}
type Command int
const (
CmdUnknown Command = iota
- CmdNone
CmdUpstream
CmdFix
CmdUnFix
@@ -130,8 +133,8 @@ func Parse(r io.Reader, ownEmails, goodLists, domains []string) (*Email, error)
}
bodyStr := string(body)
subject := msg.Header.Get("Subject")
- cmd := CmdNone
- patch, cmdStr, cmdArgs := "", "", ""
+ var cmds []*SingleCommand
+ var patch string
if !fromMe {
for _, a := range attachments {
patch = ParsePatch(a)
@@ -142,7 +145,7 @@ func Parse(r io.Reader, ownEmails, goodLists, domains []string) (*Email, error)
if patch == "" {
patch = ParsePatch(body)
}
- cmd, cmdStr, cmdArgs = extractCommand(subject + "\n" + bodyStr)
+ cmds = extractCommands(subject + "\n" + bodyStr)
}
bugIDs = append(bugIDs, extractBodyBugIDs(bodyStr, ownAddrs, domains)...)
@@ -180,9 +183,7 @@ func Parse(r io.Reader, ownEmails, goodLists, domains []string) (*Email, error)
Cc: ccList,
Body: bodyStr,
Patch: patch,
- Command: cmd,
- CommandStr: cmdStr,
- CommandArgs: cmdArgs,
+ Commands: cmds,
}
return email, nil
}
@@ -241,25 +242,35 @@ func CanonicalEmail(email string) string {
return strings.ToLower(addr.Address)
}
+func extractCommands(body string) []*SingleCommand {
+ var ret []*SingleCommand
+ for body != "" {
+ cmd, end := extractCommand(body)
+ if cmd == nil {
+ break
+ }
+ ret = append(ret, cmd)
+ body = body[end:]
+ }
+ return ret
+}
+
const commandPrefix = "#syz"
+var commandStartRe = regexp.MustCompile(`(?:^|\n)(` + regexp.QuoteMeta(commandPrefix) + `[ \t-:])`)
+
// extractCommand extracts command to syzbot from email body.
// Commands are of the following form:
// ^#syz cmd args...
-func extractCommand(body string) (cmd Command, str, args string) {
- nbody := "\n" + body
- cmdPos := -1
- for _, delim := range []string{" ", "\t", "-", ":"} {
- cmdPos = strings.Index(nbody, "\n"+commandPrefix+delim)
- if cmdPos != -1 {
- break
- }
- }
- if cmdPos == -1 {
- cmd = CmdNone
- return
+func extractCommand(body string) (*SingleCommand, int) {
+ var cmd Command
+ var str, args string
+
+ match := commandStartRe.FindStringSubmatchIndex(body)
+ if match == nil {
+ return nil, 0
}
- cmdPos += len(commandPrefix) + 1
+ cmdPos := match[2] + len(commandPrefix) + 1
for cmdPos < len(body) && unicode.IsSpace(rune(body[cmdPos])) {
cmdPos++
}
@@ -292,15 +303,17 @@ func extractCommand(body string) (cmd Command, str, args string) {
case CmdFix, CmdDup:
args = extractArgsLine(body[cmdPos+cmdEnd:])
}
- return
+ return &SingleCommand{
+ Command: cmd,
+ Str: str,
+ Args: args,
+ }, cmdPos + cmdEnd
}
func strToCmd(str string) Command {
switch str {
default:
return CmdUnknown
- case "":
- return CmdNone
case "upstream":
return CmdUpstream
case "fix", "fix:":
diff --git a/pkg/email/parser_test.go b/pkg/email/parser_test.go
index 33b2413ce..ee39d6164 100644
--- a/pkg/email/parser_test.go
+++ b/pkg/email/parser_test.go
@@ -5,7 +5,6 @@ package email
import (
"fmt"
- "reflect"
"strings"
"testing"
"time"
@@ -16,17 +15,13 @@ import (
func TestExtractCommand(t *testing.T) {
for i, test := range extractCommandTests {
t.Run(fmt.Sprint(i), func(t *testing.T) {
- cmd, str, args := extractCommand(test.body)
- if cmd != test.cmd || str != test.str || !reflect.DeepEqual(args, test.args) {
- t.Logf("expect: %v %q %q", test.cmd, test.str, test.args)
- t.Logf("got : %v %q %q", cmd, str, args)
- t.Fail()
+ cmd, _ := extractCommand(test.body)
+ if diff := cmp.Diff(test.cmd, cmd); diff != "" {
+ t.Fatal(diff)
}
- cmd, str, args = extractCommand(strings.Replace(test.body, "\n", "\r\n", -1))
- if cmd != test.cmd || str != test.str || !reflect.DeepEqual(args, test.args) {
- t.Logf("expect: %v %q %q", test.cmd, test.str, test.args)
- t.Logf("got : %v %q %q", cmd, str, args)
- t.Fail()
+ cmd, _ = extractCommand(strings.Replace(test.body, "\n", "\r\n", -1))
+ if diff := cmp.Diff(test.cmd, cmd); diff != "" {
+ t.Fatal(diff)
}
})
}
@@ -143,18 +138,18 @@ func TestParse(t *testing.T) {
var extractCommandTests = []struct {
body string
- cmd Command
- str string
- args string
+ cmd *SingleCommand
}{
{
body: `Hello,
line1
#syz fix: bar baz `,
- cmd: CmdFix,
- str: "fix:",
- args: "bar baz",
+ cmd: &SingleCommand{
+ Command: CmdFix,
+ Str: "fix:",
+ Args: "bar baz",
+ },
},
{
body: `Hello,
@@ -163,9 +158,11 @@ line1
#syz fix bar baz
line 2
`,
- cmd: CmdFix,
- str: "fix",
- args: "bar baz",
+ cmd: &SingleCommand{
+ Command: CmdFix,
+ Str: "fix",
+ Args: "bar baz",
+ },
},
{
body: `
@@ -173,26 +170,31 @@ line1
> #syz fix: bar baz
line 2
`,
- cmd: CmdNone,
- args: "",
+ cmd: nil,
},
{
body: `#syz-fix: bar baz`,
- cmd: CmdFix,
- str: "fix:",
- args: "bar baz",
+ cmd: &SingleCommand{
+ Command: CmdFix,
+ Str: "fix:",
+ Args: "bar baz",
+ },
},
{
body: `#syz-fix bar baz`,
- cmd: CmdFix,
- str: "fix",
- args: "bar baz",
+ cmd: &SingleCommand{
+ Command: CmdFix,
+ Str: "fix",
+ Args: "bar baz",
+ },
},
{
body: `#syz: fix: bar baz`,
- cmd: CmdFix,
- str: "fix:",
- args: "bar baz",
+ cmd: &SingleCommand{
+ Command: CmdFix,
+ Str: "fix:",
+ Args: "bar baz",
+ },
},
// This is unfortunate case when a command is split by email client
// due to 80-column limitation.
@@ -201,18 +203,22 @@ line 2
#syz test: git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git
locking/core
`,
- cmd: CmdTest,
- str: "test:",
- args: "git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git locking/core",
+ cmd: &SingleCommand{
+ Command: CmdTest,
+ Str: "test:",
+ Args: "git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git locking/core",
+ },
},
{
body: `
#syz test
git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git locking/core
`,
- cmd: CmdTest,
- str: "test",
- args: "git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git locking/core",
+ cmd: &SingleCommand{
+ Command: CmdTest,
+ Str: "test",
+ Args: "git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git locking/core",
+ },
},
{
body: `
@@ -221,21 +227,27 @@ git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git
locking/core
locking/core
`,
- cmd: CmdTest,
- str: "test:",
- args: "git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git locking/core",
+ cmd: &SingleCommand{
+ Command: CmdTest,
+ Str: "test:",
+ Args: "git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git locking/core",
+ },
},
{
body: `#syz test: repo commit`,
- cmd: CmdTest,
- str: "test:",
- args: "repo commit",
+ cmd: &SingleCommand{
+ Command: CmdTest,
+ Str: "test:",
+ Args: "repo commit",
+ },
},
{
body: `#syz test: repo commit`,
- cmd: CmdTest,
- str: "test:",
- args: "repo commit",
+ cmd: &SingleCommand{
+ Command: CmdTest,
+ Str: "test:",
+ Args: "repo commit",
+ },
},
{
body: `
@@ -246,32 +258,40 @@ locking/core
arg4
arg5
`,
- cmd: cmdTest5,
- str: "test_5_arg_cmd",
- args: "arg1 arg2 arg3 arg4 arg5",
+ cmd: &SingleCommand{
+ Command: cmdTest5,
+ Str: "test_5_arg_cmd",
+ Args: "arg1 arg2 arg3 arg4 arg5",
+ },
},
{
body: `#syz test_5_arg_cmd arg1 arg2 arg3 arg4 arg5`,
- cmd: cmdTest5,
- str: "test_5_arg_cmd",
- args: "arg1 arg2 arg3 arg4 arg5",
+ cmd: &SingleCommand{
+ Command: cmdTest5,
+ Str: "test_5_arg_cmd",
+ Args: "arg1 arg2 arg3 arg4 arg5",
+ },
},
{
body: `
#syz test_5_arg_cmd arg1
arg2`,
- cmd: cmdTest5,
- str: "test_5_arg_cmd",
- args: "arg1 arg2",
+ cmd: &SingleCommand{
+ Command: cmdTest5,
+ Str: "test_5_arg_cmd",
+ Args: "arg1 arg2",
+ },
},
{
body: `
#syz test_5_arg_cmd arg1
arg2
`,
- cmd: cmdTest5,
- str: "test_5_arg_cmd",
- args: "arg1 arg2",
+ cmd: &SingleCommand{
+ Command: cmdTest5,
+ Str: "test_5_arg_cmd",
+ Args: "arg1 arg2",
+ },
},
{
body: `
@@ -280,9 +300,11 @@ arg2
`,
- cmd: cmdTest5,
- str: "test_5_arg_cmd",
- args: "arg1 arg2",
+ cmd: &SingleCommand{
+ Command: cmdTest5,
+ Str: "test_5_arg_cmd",
+ Args: "arg1 arg2",
+ },
},
{
body: `
@@ -291,27 +313,33 @@ arg1 arg2 arg3
arg4 arg5
`,
- cmd: CmdFix,
- str: "fix:",
- args: "arg1 arg2 arg3",
+ cmd: &SingleCommand{
+ Command: CmdFix,
+ Str: "fix:",
+ Args: "arg1 arg2 arg3",
+ },
},
{
body: `
#syz fix: arg1 arg2 arg3
arg4 arg5
`,
- cmd: CmdFix,
- str: "fix:",
- args: "arg1 arg2 arg3",
+ cmd: &SingleCommand{
+ Command: CmdFix,
+ Str: "fix:",
+ Args: "arg1 arg2 arg3",
+ },
},
{
body: `
#syz dup: title goes here
baz
`,
- cmd: CmdDup,
- str: "dup:",
- args: "title goes here",
+ cmd: &SingleCommand{
+ Command: CmdDup,
+ Str: "dup:",
+ Args: "title goes here",
+ },
},
{
body: `
@@ -319,25 +347,43 @@ baz
title on the next line goes here
but not this one
`,
- cmd: CmdDup,
- str: "dup",
- args: "title on the next line goes here",
+ cmd: &SingleCommand{
+ Command: CmdDup,
+ Str: "dup",
+ Args: "title on the next line goes here",
+ },
},
{
body: `
#syz foo bar
baz
`,
- cmd: CmdUnknown,
- str: "foo",
+ cmd: &SingleCommand{
+ Command: CmdUnknown,
+ Str: "foo",
+ },
},
{
body: `
#syz set subsystems: net, fs
`,
- cmd: CmdSet,
- str: "set",
- args: "subsystems: net, fs",
+ cmd: &SingleCommand{
+ Command: CmdSet,
+ Str: "set",
+ Args: "subsystems: net, fs",
+ },
+ },
+ {
+ body: `
+#syz fix: abcd
+#syz fix: xyz
+`,
+ // Should only extract the first one.
+ cmd: &SingleCommand{
+ Command: CmdFix,
+ Str: "fix:",
+ Args: "abcd",
+ },
},
}
@@ -385,10 +431,14 @@ To unsubscribe from this group and stop receiving emails from it, send an email
To post to this group, send email to syzkaller@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/syzkaller/abcdef@google.com.
For more options, visit https://groups.google.com/d/optout.`,
- Patch: "",
- Command: CmdFix,
- CommandStr: "fix:",
- CommandArgs: "arg1 arg2 arg3",
+ Patch: "",
+ Commands: []*SingleCommand{
+ {
+ Command: CmdFix,
+ Str: "fix:",
+ Args: "arg1 arg2 arg3",
+ },
+ },
}},
{`Date: Sun, 7 May 2017 19:54:00 -0700
@@ -410,8 +460,7 @@ last line`,
Cc: []string{"bob@example.com"},
Body: `text body
last line`,
- Patch: "",
- Command: CmdNone,
+ Patch: "",
}},
{`Date: Sun, 7 May 2017 19:54:00 -0700
@@ -434,10 +483,14 @@ last line`,
text body
second line
last line`,
- Patch: "",
- Command: CmdInvalid,
- CommandStr: "invalid",
- CommandArgs: "",
+ Patch: "",
+ Commands: []*SingleCommand{
+ {
+ Command: CmdInvalid,
+ Str: "invalid",
+ Args: "",
+ },
+ },
}},
{`Date: Sun, 7 May 2017 19:54:00 -0700
@@ -461,9 +514,13 @@ last line
second line
last line
#syz command`,
- Patch: "",
- Command: CmdUnknown,
- CommandStr: "command",
+ Patch: "",
+ Commands: []*SingleCommand{
+ {
+ Command: CmdUnknown,
+ Str: "command",
+ },
+ },
}},
{`Date: Sun, 7 May 2017 19:54:00 -0700
@@ -514,8 +571,6 @@ index 85e5546cd791..949ea4574412 100644
spin_unlock(&kcov->lock);
return;
`,
- Command: CmdNone,
- CommandArgs: "",
}},
{`Date: Sun, 7 May 2017 19:54:00 -0700
@@ -627,9 +682,13 @@ index 3d85747bd86e..a257b872a53d 100644
error = vfs_statx(dfd, filename, flags, &stat, mask);
if (error)
`,
- Command: CmdTest,
- CommandStr: "test",
- CommandArgs: "commit 59372bbf3abd5b24a7f6f676a3968685c280f955",
+ Commands: []*SingleCommand{
+ {
+ Command: CmdTest,
+ Str: "test",
+ Args: "commit 59372bbf3abd5b24a7f6f676a3968685c280f955",
+ },
+ },
}},
{`Sender: syzkaller-bugs@googlegroups.com
@@ -677,9 +736,13 @@ d
#syz dup: BUG: unable to handle kernel NULL pointer dereference in corrupted
`,
- Command: CmdDup,
- CommandStr: "dup:",
- CommandArgs: "BUG: unable to handle kernel NULL pointer dereference in corrupted",
+ Commands: []*SingleCommand{
+ {
+ Command: CmdDup,
+ Str: "dup:",
+ Args: "BUG: unable to handle kernel NULL pointer dereference in corrupted",
+ },
+ },
}},
{`Sender: syzkaller-bugs@googlegroups.com
@@ -694,9 +757,13 @@ BUG: unable to handle kernel NULL pointer dereference in corrupted
Body: `#syz dup:
BUG: unable to handle kernel NULL pointer dereference in corrupted
`,
- Command: CmdDup,
- CommandStr: "dup:",
- CommandArgs: "BUG: unable to handle kernel NULL pointer dereference in corrupted",
+ Commands: []*SingleCommand{
+ {
+ Command: CmdDup,
+ Str: "dup:",
+ Args: "BUG: unable to handle kernel NULL pointer dereference in corrupted",
+ },
+ },
}},
{`Sender: syzkaller-bugs@googlegroups.com
@@ -711,9 +778,13 @@ When freeing a lockf struct that already is part of a linked list, make sure to
Body: `#syz fix:
When freeing a lockf struct that already is part of a linked list, make sure to
`,
- Command: CmdFix,
- CommandStr: "fix:",
- CommandArgs: "When freeing a lockf struct that already is part of a linked list, make sure to",
+ Commands: []*SingleCommand{
+ {
+ Command: CmdFix,
+ Str: "fix:",
+ Args: "When freeing a lockf struct that already is part of a linked list, make sure to",
+ },
+ },
}},
{`Date: Sun, 7 May 2017 19:54:00 -0700
Message-ID: <123>
@@ -723,16 +794,20 @@ To: syzbot <foo+4564456@bar.com>
nothing to see here`,
Email{
- BugIDs: []string{"4564456"},
- MessageID: "<123>",
- Date: time.Date(2017, time.May, 7, 19, 54, 0, 0, parseTestZone),
- Subject: "#syz test: git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git master",
- Author: "bob@example.com",
- Cc: []string{"bob@example.com"},
- Body: `nothing to see here`,
- Command: CmdTest,
- CommandStr: "test:",
- CommandArgs: "git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git master",
+ BugIDs: []string{"4564456"},
+ MessageID: "<123>",
+ Date: time.Date(2017, time.May, 7, 19, 54, 0, 0, parseTestZone),
+ Subject: "#syz test: git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git master",
+ Author: "bob@example.com",
+ Cc: []string{"bob@example.com"},
+ Body: `nothing to see here`,
+ Commands: []*SingleCommand{
+ {
+ Command: CmdTest,
+ Str: "test:",
+ Args: "git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git master",
+ },
+ },
}},
{`Date: Sun, 7 May 2017 19:54:00 -0700
Message-ID: <123>
@@ -750,7 +825,6 @@ nothing to see here`,
MailingList: "list@googlegroups.com",
Cc: []string{"list@googlegroups.com", "user@mail.com"},
Body: `nothing to see here`,
- Command: CmdNone,
}},
{`Date: Sun, 7 May 2017 19:54:00 -0700
Message-ID: <123>
@@ -768,7 +842,6 @@ nothing to see here`,
MailingList: "list@googlegroups.com",
Cc: []string{"list@googlegroups.com", "user2@mail.com", "user@mail.com"},
Body: `nothing to see here`,
- Command: CmdNone,
}},
// A faulty case, just check we handle it normally.
{`Date: Sun, 7 May 2017 19:54:00 -0700
@@ -786,7 +859,6 @@ nothing to see here`,
MailingList: "list@googlegroups.com",
Cc: []string{"list@googlegroups.com", "user2@mail.com"},
Body: `nothing to see here`,
- Command: CmdNone,
}},
{`Sender: syzkaller-bugs@googlegroups.com
Subject: Re: BUG: unable to handle kernel NULL pointer dereference in
@@ -812,9 +884,13 @@ f950fddb9ea6bdb5e39
Body: `#syz
test: https://github.com/torvalds/linux.git 7b5bb460defa107dd2e82f950fddb9ea6bdb5e39
`,
- Command: CmdTest,
- CommandStr: "test:",
- CommandArgs: "https://github.com/torvalds/linux.git 7b5bb460defa107dd2e82f950fddb9ea6bdb5e39",
+ Commands: []*SingleCommand{
+ {
+ Command: CmdTest,
+ Str: "test:",
+ Args: "https://github.com/torvalds/linux.git 7b5bb460defa107dd2e82f950fddb9ea6bdb5e39",
+ },
+ },
}},
{`Sender: syzkaller-bugs@googlegroups.com
Subject: [PATCH] Some patch
@@ -837,7 +913,6 @@ Reported-by: syzbot <foo+223c7461c58c58a4cb10@bar.com>
Cc: []string{"bar@foo.com", "someone@foo.com"},
Body: `Reported-by: syzbot <foo+223c7461c58c58a4cb10@bar.com>
`,
- Command: CmdNone,
}},
{`Sender: syzkaller-bugs@googlegroups.com
Subject: [PATCH] Some patch
@@ -859,7 +934,6 @@ Link: https://bar.com/bug?extid=223c7461c58c58a4cb10@bar.com
Cc: []string{"bar@foo.com", "someone@foo.com"},
Body: `Link: https://bar.com/bug?extid=223c7461c58c58a4cb10@bar.com
`,
- Command: CmdNone,
}},
{`Sender: syzkaller-bugs@googlegroups.com
@@ -885,7 +959,6 @@ Reported-by: syzbot <foo+9909090909090909@bar.com>
Body: `Reported-by: syzbot <foo+223c7461c58c58a4cb10@bar.com>
Reported-by: syzbot <foo+9909090909090909@bar.com>
`,
- Command: CmdNone,
}},
{`Sender: syzkaller-bugs@googlegroups.com
Subject: [PATCH] Some patch
@@ -909,7 +982,6 @@ Reported-by: syzbot <foo+223c7461c58c58a4cb10@bar.com>
Cc: []string{"bar@foo.com", "someone@foo.com"},
Body: `Reported-by: syzbot <foo+223c7461c58c58a4cb10@bar.com>
`,
- Command: CmdNone,
}},
{`Sender: syzkaller-bugs@googlegroups.com
Subject: Some discussion
@@ -937,6 +1009,41 @@ Some text
Author: "bar@foo.com",
Cc: []string{"bar@foo.com", "someone@foo.com"},
Body: "Some text\n",
- Command: CmdNone,
+ }},
+ {`Sender: syzkaller-bugs@googlegroups.com
+Subject: Re: BUG: unable to handle kernel NULL pointer dereference in
+ sock_poll
+To: syzbot <syzbot+344bb0f46d7719cd9483@syzkaller.appspotmail.com>
+From: bar <bar@foo.com>
+Message-ID: <1250334f-7220-2bff-5d87-b87573758d81@bar.com>
+Date: Sun, 7 May 2017 19:54:00 -0700
+MIME-Version: 1.0
+Content-Type: text/plain; charset="UTF-8"
+Content-Language: en-US
+Content-Transfer-Encoding: quoted-printable
+
+#syz test: aaa bbb
+#syz test: ccc ddd
+`, Email{
+ MessageID: "<1250334f-7220-2bff-5d87-b87573758d81@bar.com>",
+ Date: time.Date(2017, time.May, 7, 19, 54, 0, 0, parseTestZone),
+ Subject: "Re: BUG: unable to handle kernel NULL pointer dereference in sock_poll",
+ Author: "bar@foo.com",
+ Cc: []string{"bar@foo.com", "syzbot@syzkaller.appspotmail.com"},
+ Body: `#syz test: aaa bbb
+#syz test: ccc ddd
+`,
+ Commands: []*SingleCommand{
+ {
+ Command: CmdTest,
+ Str: "test:",
+ Args: "aaa bbb",
+ },
+ {
+ Command: CmdTest,
+ Str: "test:",
+ Args: "ccc ddd",
+ },
+ },
}},
}
diff --git a/pkg/email/reply.go b/pkg/email/reply.go
index 65aec4509..28229ba62 100644
--- a/pkg/email/reply.go
+++ b/pkg/email/reply.go
@@ -9,8 +9,8 @@ import (
"strings"
)
-func FormReply(email, reply string) string {
- s := bufio.NewScanner(strings.NewReader(email))
+func FormReply(email *Email, reply string) string {
+ s := bufio.NewScanner(strings.NewReader(email.Body))
out := new(bytes.Buffer)
replied := false
for s.Scan() {
@@ -21,7 +21,12 @@ func FormReply(email, reply string) string {
}
out.Write(ln)
out.WriteByte('\n')
- if !replied && bytes.HasPrefix(ln, []byte(commandPrefix)) {
+ if len(email.Commands) > 1 {
+ // If there are several commands, we cannot precisely attribute replies.
+ // TODO: that's possible, but such a refactoring does not seem to be worth it
+ // at the time.
+ continue
+ } else if !replied && bytes.HasPrefix(ln, []byte(commandPrefix)) {
replied = true
writeReply(out, reply)
}
diff --git a/pkg/email/reply_test.go b/pkg/email/reply_test.go
index 4e6256ccf..8ceb08f98 100644
--- a/pkg/email/reply_test.go
+++ b/pkg/email/reply_test.go
@@ -22,16 +22,17 @@ func TestFormReply(t *testing.T) {
}
var formReplyTests = []struct {
- email string
+ email *Email
reply string
result string
}{
{
- email: `line1
+ email: &Email{
+ Body: `line1
line2
#syz foo
line3
-`,
+`},
reply: "this is reply",
result: `> line1
> line2
@@ -43,10 +44,11 @@ this is reply
`,
},
{
- email: `
+ email: &Email{
+ Body: `
#syz-fix
line2
-`,
+`},
reply: "this is reply",
result: `>
> #syz-fix
@@ -57,10 +59,11 @@ this is reply
`,
},
{
- email: `
+ email: &Email{
+ Body: `
#syz: fix
line2
-`,
+`},
reply: "this is reply",
result: `>
> #syz: fix
@@ -71,11 +74,12 @@ this is reply
`,
},
{
- email: `> line1
+ email: &Email{
+ Body: `> line1
> line2
#syz foo
line3
-`,
+`},
reply: "this is reply\n",
result: `>> line1
>> line2
@@ -87,9 +91,10 @@ this is reply
`,
},
{
- email: `line1
+ email: &Email{
+ Body: `line1
line2
-#syz foo`,
+#syz foo`},
reply: "this is reply 1\nthis is reply 2",
result: `> line1
> line2
@@ -101,9 +106,10 @@ this is reply 2
`,
},
{
- email: `line1
+ email: &Email{
+ Body: `line1
line2
-`,
+`},
reply: "this is reply",
result: `> line1
> line2
@@ -112,4 +118,26 @@ this is reply
`,
},
+ {
+ email: &Email{
+ Body: `line1
+#syz foo
+line2
+#syz bar`,
+ Commands: []*SingleCommand{
+ {},
+ {},
+ },
+ },
+ reply: "this is reply 1\nthis is reply 2",
+ result: `> line1
+> #syz foo
+> line2
+> #syz bar
+
+this is reply 1
+this is reply 2
+
+`,
+ },
}