aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAleksandr Nogikh <nogikh@google.com>2025-02-18 16:33:07 +0100
committerAleksandr Nogikh <nogikh@google.com>2025-02-19 14:52:44 +0000
commitb257a9b7546c59d44cd69160b5a65a1bf1f050eb (patch)
tree8c05de868d70660622a1871b739e99a6cfe5d6e6
parent3b79d489db1ad98df7f1986a4695f581e6be9be3 (diff)
syz-cluster/pkg/report: add an email template
The first revision of the email template that will be used for reporting the findings. This PR adds more fields to the pkg/api package, but these are not filled by the implementation yet. That will be done separately.
-rw-r--r--syz-cluster/pkg/api/api.go29
-rw-r--r--syz-cluster/pkg/report/email.go40
-rw-r--r--syz-cluster/pkg/report/email_test.go71
-rw-r--r--syz-cluster/pkg/report/template.txt57
-rw-r--r--syz-cluster/pkg/report/testdata/1.in.json43
-rw-r--r--syz-cluster/pkg/report/testdata/1.moderation.txt56
-rw-r--r--syz-cluster/pkg/report/testdata/1.upstream.txt49
-rw-r--r--syz-cluster/pkg/service/finding.go3
-rw-r--r--syz-cluster/reporter/api_test.go4
9 files changed, 340 insertions, 12 deletions
diff --git a/syz-cluster/pkg/api/api.go b/syz-cluster/pkg/api/api.go
index b7d2992ce..535808e29 100644
--- a/syz-cluster/pkg/api/api.go
+++ b/syz-cluster/pkg/api/api.go
@@ -119,18 +119,29 @@ type NewSession struct {
}
type SessionReport struct {
- ID string `json:"id"`
- Moderation bool `json:"moderation"`
- // TODO: add some session info?
- Series *Series `json:"series"`
- Findings []*Finding `json:"findings"`
- Link string `json:"link"` // URL to the web dashboard.
+ ID string `json:"id"`
+ Cc []string `json:"cc"`
+ Moderation bool `json:"moderation"`
+ BaseRepo string `json:"base_repo"`
+ BaseCommit string `json:"base_commit"`
+ Series *Series `json:"series"`
+ Findings []*Finding `json:"findings"`
+ Link string `json:"link"` // URL to the web dashboard.
}
type Finding struct {
- Title string `json:"title"`
- Report []byte `json:"report"`
- LogURL string `json:"log_url"`
+ Title string `json:"title"`
+ Report string `json:"report"`
+ LogURL string `json:"log_url"`
+ Build BuildInfo `json:"build"`
+ LinkCRepro string `json:"c_repro"`
+ LinkSyzRepro string `json:"syz_repro"`
+}
+
+type BuildInfo struct {
+ Arch string `json:"arch"`
+ Compiler string `json:"compiler"`
+ ConfigLink string `json:"config_link"`
}
// Let them stay here until we find a better place.
diff --git a/syz-cluster/pkg/report/email.go b/syz-cluster/pkg/report/email.go
new file mode 100644
index 000000000..8317d46a6
--- /dev/null
+++ b/syz-cluster/pkg/report/email.go
@@ -0,0 +1,40 @@
+// Copyright 2025 syzkaller project authors. All rights reserved.
+// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
+
+package report
+
+import (
+ "bytes"
+ "embed"
+ "html/template"
+
+ "github.com/google/syzkaller/syz-cluster/pkg/api"
+)
+
+type Config struct {
+ Name string
+ DocsLink string
+ SupportEmail string
+}
+
+//go:embed template.txt
+var templateFS embed.FS
+
+func Render(rep *api.SessionReport, config *Config) ([]byte, error) {
+ tmpl, err := template.ParseFS(templateFS, "template.txt")
+ if err != nil {
+ return nil, err
+ }
+ data := struct {
+ Report *api.SessionReport
+ Config *Config
+ }{
+ Report: rep,
+ Config: config,
+ }
+ var buf bytes.Buffer
+ if err := tmpl.Execute(&buf, data); err != nil {
+ return nil, err
+ }
+ return buf.Bytes(), nil
+}
diff --git a/syz-cluster/pkg/report/email_test.go b/syz-cluster/pkg/report/email_test.go
new file mode 100644
index 000000000..5f33fbfda
--- /dev/null
+++ b/syz-cluster/pkg/report/email_test.go
@@ -0,0 +1,71 @@
+// Copyright 2025 syzkaller project authors. All rights reserved.
+// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
+
+package report
+
+import (
+ "encoding/json"
+ "flag"
+ "os"
+ "path/filepath"
+ "strings"
+ "testing"
+
+ "github.com/google/syzkaller/syz-cluster/pkg/api"
+ "github.com/stretchr/testify/assert"
+)
+
+var flagWrite = flag.Bool("write", false, "overwrite out.txt files")
+
+func TestRender(t *testing.T) {
+ config := &Config{
+ Name: "syzbot",
+ DocsLink: "http://docs/link",
+ SupportEmail: "support@email.com",
+ }
+ flag.Parse()
+ basePath := "testdata"
+ files, err := os.ReadDir(basePath)
+ if err != nil {
+ t.Fatal(err)
+ }
+ for _, file := range files {
+ if filepath.Ext(file.Name()) != ".json" {
+ continue
+ }
+ fullName := file.Name()
+ name := strings.TrimSuffix(fullName, ".in.json")
+ t.Run(name, func(t *testing.T) {
+ t.Parallel()
+ inPath := filepath.Join(basePath, fullName)
+ inputData, err := os.ReadFile(inPath)
+ assert.NoError(t, err)
+
+ var report api.SessionReport
+ err = json.Unmarshal(inputData, &report)
+ assert.NoError(t, err)
+
+ for _, value := range []bool{false, true} {
+ report.Moderation = value
+ suffix := "upstream"
+ if value {
+ suffix = "moderation"
+ }
+ t.Run(suffix, func(t *testing.T) {
+ output, err := Render(&report, config)
+ assert.NoError(t, err)
+
+ outPath := filepath.Join(basePath, name+"."+suffix+".txt")
+ if *flagWrite {
+ err := os.WriteFile(outPath, output, 0644)
+ assert.NoError(t, err)
+ } else {
+ expected, err := os.ReadFile(outPath)
+ assert.NoError(t, err)
+ assert.Equal(t, expected, output)
+ }
+ })
+ }
+ })
+ }
+}
diff --git a/syz-cluster/pkg/report/template.txt b/syz-cluster/pkg/report/template.txt
new file mode 100644
index 000000000..687cec214
--- /dev/null
+++ b/syz-cluster/pkg/report/template.txt
@@ -0,0 +1,57 @@
+{{.Config.Name}} has processed the following series
+
+[v{{.Report.Series.Version}}] {{.Report.Series.Title}}
+{{.Report.Series.Link}}
+{{- range .Report.Series.Patches}}
+* {{.Title}}
+{{- end}}
+
+and found the following issues:
+{{- range .Report.Findings}}
+* {{.Title}}
+{{- end}}
+
+The series was applied to the following base tree:
+* Tree: {{.Report.BaseRepo}}
+* Commit: {{.Report.BaseCommit}}
+
+Full report is available here:
+{{.Report.Link}}
+
+{{- range .Report.Findings}}
+
+***
+
+{{.Title}}
+{{if .Build.Arch}}
+arch: {{.Build.Arch}}
+{{- end}}
+{{- if .Build.Compiler}}
+compiler: {{.Build.Compiler}}
+{{- end}}
+{{- if .Build.ConfigLink}}
+config: {{.Build.ConfigLink}}
+{{- end}}
+{{- if .LinkCRepro}}
+C repro: {{.LinkCRepro}}
+{{- end}}
+{{- if .LinkSyzRepro}}
+syz repro: {{.LinkSyzRepro}}
+{{- end}}
+
+{{.Report -}}
+{{end}}
+
+---
+This report is generated by a bot. It may contain errors.
+See {{.Config.DocsLink}} for more information about {{.Config.Name}}.
+{{.Config.Name}} engineers can be reached at {{.Config.SupportEmail}}.
+
+{{- if .Report.Moderation}}
+
+The email will later be sent to:
+{{.Report.Cc}}
+
+If the report looks fine to you, reply with:
+#syz upstream
+{{end}}
diff --git a/syz-cluster/pkg/report/testdata/1.in.json b/syz-cluster/pkg/report/testdata/1.in.json
new file mode 100644
index 000000000..e6ff0696e
--- /dev/null
+++ b/syz-cluster/pkg/report/testdata/1.in.json
@@ -0,0 +1,43 @@
+{
+ "id": "abcd",
+ "base_repo": "git://repo",
+ "base_commit": "abcd0123",
+ "series": {
+ "title": "Series title",
+ "version": 2,
+ "link": "http://link/to/series",
+ "patches": [
+ {
+ "title": "first patch"
+ },
+ {
+ "title": "second patch"
+ }
+ ]
+ },
+ "findings": [
+ {
+ "title": "WARNING in abcd",
+ "report": "Report Line A\nReport Line B\nReport Line C",
+ "c_repro": "http://link/to/c/repro",
+ "syz_repro": "http://link/to/syz/repro",
+ "build": {
+ "arch": "amd64",
+ "config_link": "http://link/to/config/1",
+ "compiler": "clang"
+ }
+ },
+ {
+ "title": "KASAN: use-after-free Write in abcd",
+ "report": "Report Line D\nReport Line E\nReport Line F",
+ "syz_repro": "http://link/to/syz/repro2",
+ "build": {
+ "arch": "arm64",
+ "config_link": "http://link/to/config/2",
+ "compiler": "clang"
+ }
+ }
+ ],
+ "cc": ["a@a.com", "b@b.com"],
+ "link": "http://some/link/to/report"
+}
diff --git a/syz-cluster/pkg/report/testdata/1.moderation.txt b/syz-cluster/pkg/report/testdata/1.moderation.txt
new file mode 100644
index 000000000..7f5a98f2b
--- /dev/null
+++ b/syz-cluster/pkg/report/testdata/1.moderation.txt
@@ -0,0 +1,56 @@
+syzbot has processed the following series
+
+[v2] Series title
+http://link/to/series
+* first patch
+* second patch
+
+and found the following issues:
+* WARNING in abcd
+* KASAN: use-after-free Write in abcd
+
+The series was applied to the following base tree:
+* Tree: git://repo
+* Commit: abcd0123
+
+Full report is available here:
+http://some/link/to/report
+
+***
+
+WARNING in abcd
+
+arch: amd64
+compiler: clang
+config: http://link/to/config/1
+C repro: http://link/to/c/repro
+syz repro: http://link/to/syz/repro
+
+Report Line A
+Report Line B
+Report Line C
+
+***
+
+KASAN: use-after-free Write in abcd
+
+arch: arm64
+compiler: clang
+config: http://link/to/config/2
+syz repro: http://link/to/syz/repro2
+
+Report Line D
+Report Line E
+Report Line F
+
+---
+This report is generated by a bot. It may contain errors.
+See http://docs/link for more information about syzbot.
+syzbot engineers can be reached at support@email.com.
+
+The email will later be sent to:
+[a@a.com b@b.com]
+
+If the report looks fine to you, reply with:
+#syz upstream
+
diff --git a/syz-cluster/pkg/report/testdata/1.upstream.txt b/syz-cluster/pkg/report/testdata/1.upstream.txt
new file mode 100644
index 000000000..510e82cd2
--- /dev/null
+++ b/syz-cluster/pkg/report/testdata/1.upstream.txt
@@ -0,0 +1,49 @@
+syzbot has processed the following series
+
+[v2] Series title
+http://link/to/series
+* first patch
+* second patch
+
+and found the following issues:
+* WARNING in abcd
+* KASAN: use-after-free Write in abcd
+
+The series was applied to the following base tree:
+* Tree: git://repo
+* Commit: abcd0123
+
+Full report is available here:
+http://some/link/to/report
+
+***
+
+WARNING in abcd
+
+arch: amd64
+compiler: clang
+config: http://link/to/config/1
+C repro: http://link/to/c/repro
+syz repro: http://link/to/syz/repro
+
+Report Line A
+Report Line B
+Report Line C
+
+***
+
+KASAN: use-after-free Write in abcd
+
+arch: arm64
+compiler: clang
+config: http://link/to/config/2
+syz repro: http://link/to/syz/repro2
+
+Report Line D
+Report Line E
+Report Line F
+
+---
+This report is generated by a bot. It may contain errors.
+See http://docs/link for more information about syzbot.
+syzbot engineers can be reached at support@email.com.
diff --git a/syz-cluster/pkg/service/finding.go b/syz-cluster/pkg/service/finding.go
index b0530a42c..bb605ba73 100644
--- a/syz-cluster/pkg/service/finding.go
+++ b/syz-cluster/pkg/service/finding.go
@@ -67,10 +67,11 @@ func (s *FindingService) List(ctx context.Context, sessionID string) ([]*api.Fin
Title: item.Title,
LogURL: "TODO", // TODO: where to take it from?
}
- finding.Report, err = blob.ReadAllBytes(s.blobStorage, item.ReportURI)
+ bytes, err := blob.ReadAllBytes(s.blobStorage, item.ReportURI)
if err != nil {
return nil, fmt.Errorf("failed to read the report: %w", err)
}
+ finding.Report = string(bytes)
ret = append(ret, finding)
}
return ret, nil
diff --git a/syz-cluster/reporter/api_test.go b/syz-cluster/reporter/api_test.go
index b4933afd7..22ccb13e8 100644
--- a/syz-cluster/reporter/api_test.go
+++ b/syz-cluster/reporter/api_test.go
@@ -80,12 +80,12 @@ func TestAPIReportFlow(t *testing.T) {
Findings: []*api.Finding{
{
Title: "finding 0",
- Report: []byte("report 0"),
+ Report: "report 0",
LogURL: "TODO", // TODO
},
{
Title: "finding 1",
- Report: []byte("report 1"),
+ Report: "report 1",
LogURL: "TODO", // TODO
},
},