From 0d9181eeec1e80722aca2e710b0a1a9d3c7de073 Mon Sep 17 00:00:00 2001 From: Aleksandr Nogikh Date: Tue, 24 Jan 2023 16:28:45 +0100 Subject: dashboard: introduce the update_report API call The update_report API can be used to re-fill the missing report details after a crash has already been sent to syzbot. --- dashboard/app/api.go | 31 +++++++++++++++++++++++++++++ dashboard/app/reporting_test.go | 43 +++++++++++++++++++++++++++++++++++++++++ dashboard/dashapi/dashapi.go | 10 ++++++++++ 3 files changed, 84 insertions(+) diff --git a/dashboard/app/api.go b/dashboard/app/api.go index 5e36b4079..2980e4234 100644 --- a/dashboard/app/api.go +++ b/dashboard/app/api.go @@ -61,6 +61,7 @@ var apiNamespaceHandlers = map[string]APINamespaceHandler{ "upload_commits": apiUploadCommits, "bug_list": apiBugList, "load_bug": apiLoadBug, + "update_report": apiUpdateReport, "add_build_assets": apiAddBuildAssets, } @@ -1108,6 +1109,36 @@ func apiBugList(c context.Context, ns string, r *http.Request, payload []byte) ( return resp, nil } +func apiUpdateReport(c context.Context, ns string, r *http.Request, payload []byte) (interface{}, error) { + req := new(dashapi.UpdateReportReq) + if err := json.Unmarshal(payload, req); err != nil { + return nil, fmt.Errorf("failed to unmarshal request: %v", err) + } + bug := new(Bug) + bugKey := db.NewKey(c, "Bug", req.BugID, 0, nil) + if err := db.Get(c, bugKey, bug); err != nil { + return nil, fmt.Errorf("failed to get bug: %v", err) + } + if bug.Namespace != ns { + return nil, fmt.Errorf("no such bug") + } + tx := func(c context.Context) error { + crash := new(Crash) + crashKey := db.NewKey(c, "Crash", "", req.CrashID, bugKey) + if err := db.Get(c, crashKey, crash); err != nil { + return fmt.Errorf("failed to query the crash: %v", err) + } + if req.GuiltyFiles != nil { + crash.ReportElements.GuiltyFiles = *req.GuiltyFiles + } + if _, err := db.Put(c, crashKey, crash); err != nil { + return fmt.Errorf("failed to put reported crash: %v", err) + } + return nil + } + return nil, db.RunInTransaction(c, tx, &db.TransactionOptions{Attempts: 5}) +} + func apiLoadBug(c context.Context, ns string, r *http.Request, payload []byte) (interface{}, error) { req := new(dashapi.LoadBugReq) if err := json.Unmarshal(payload, req); err != nil { diff --git a/dashboard/app/reporting_test.go b/dashboard/app/reporting_test.go index a594e8356..49e791e16 100644 --- a/dashboard/app/reporting_test.go +++ b/dashboard/app/reporting_test.go @@ -11,6 +11,7 @@ import ( "testing" "time" + "github.com/google/go-cmp/cmp" "github.com/google/syzkaller/dashboard/dashapi" "github.com/google/syzkaller/pkg/email" "github.com/google/syzkaller/sys/targets" @@ -1008,6 +1009,48 @@ func TestFullBugInfo(t *testing.T) { } } +func TestUpdateReportApi(t *testing.T) { + c := NewCtx(t) + defer c.Close() + + build := testBuild(1) + c.client.UploadBuild(build) + + // Report a crash. + c.client.ReportCrash(testCrashWithRepro(build, 1)) + c.client.pollBug() + + listResp, err := c.client.BugList() + c.expectOK(err) + c.expectEQ(len(listResp.List), 1) + + // Load the bug info. + bugID := listResp.List[0] + rep, err := c.client.LoadBug(bugID) + c.expectOK(err) + + // Now update the crash. + setGuiltyFiles := []string{"fs/a.c", "net/b.c"} + err = c.client.UpdateReport(&dashapi.UpdateReportReq{ + BugID: bugID, + CrashID: rep.CrashID, + GuiltyFiles: &setGuiltyFiles, + }) + c.expectOK(err) + + // And make sure it's been updated. + ret, err := c.client.LoadBug(bugID) + if err != nil { + t.Fatal(err) + } + if ret.ReportElements == nil { + t.Fatalf("ReportElements is nil") + } + if diff := cmp.Diff(ret.ReportElements.GuiltyFiles, setGuiltyFiles); diff != "" { + t.Fatal(diff) + } +} + func TestReportDecommissionedBugs(t *testing.T) { c := NewCtx(t) defer c.Close() diff --git a/dashboard/dashapi/dashapi.go b/dashboard/dashapi/dashapi.go index 17cd8df91..49f586250 100644 --- a/dashboard/dashapi/dashapi.go +++ b/dashboard/dashapi/dashapi.go @@ -685,6 +685,16 @@ func (dash *Dashboard) LoadFullBug(req *LoadFullBugReq) (*FullBugInfo, error) { return resp, err } +type UpdateReportReq struct { + BugID string + CrashID int64 + GuiltyFiles *[]string +} + +func (dash *Dashboard) UpdateReport(req *UpdateReportReq) error { + return dash.Query("update_report", req, nil) +} + type ( BugStatus int BugStatusReason string -- cgit mrf-deployment