aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAleksandr Nogikh <nogikh@google.com>2026-01-15 12:50:59 +0100
committerAleksandr Nogikh <nogikh@google.com>2026-01-15 12:26:32 +0000
commite30f059fce4242956bd289e6690b150ddc6cd0d5 (patch)
treef68cba31f5d79a20e4dea1fe7860595de652a987
parent41cfbc00ddb9f36db18d9e02ddd517d65ae1177c (diff)
dashboard: add a manuallyUpstreamed helper
This helper function can be used in the reporting filtering rules to skip certain reporting stages depending on whether the previous stage(s) have been manually upstreamed. Add tests that it does have the intended effect. Cc #6554.
-rw-r--r--dashboard/app/app_test.go40
-rw-r--r--dashboard/app/reporting.go8
-rw-r--r--dashboard/app/reporting_test.go50
3 files changed, 98 insertions, 0 deletions
diff --git a/dashboard/app/app_test.go b/dashboard/app/app_test.go
index d4c9f765f..96861dfa5 100644
--- a/dashboard/app/app_test.go
+++ b/dashboard/app/app_test.go
@@ -631,6 +631,44 @@ var testConfig = &GlobalConfig{
},
},
},
+ "skip-stage": {
+ AccessLevel: AccessPublic,
+ Key: "publickeypublickeypublickey",
+ Clients: map[string]string{
+ clientSkipStage: keySkipStage,
+ },
+ Repos: []KernelRepo{
+ {
+ URL: "git://syzkaller.org/access-public.git",
+ Branch: "access-public",
+ Alias: "access-public",
+ },
+ },
+ Reporting: []Reporting{
+ {
+ Name: "reporting1",
+ DailyLimit: 1000,
+ Config: &TestConfig{Index: 1},
+ Embargo: 4 * 24 * time.Hour,
+ },
+ {
+ Name: "reporting2",
+ DailyLimit: 1000,
+ Config: &TestConfig{Index: 2},
+ Filter: func(bug *Bug) FilterResult {
+ if bug.manuallyUpstreamed("reporting1") {
+ return FilterSkip
+ }
+ return FilterReport
+ },
+ },
+ {
+ Name: "reporting3",
+ DailyLimit: 1000,
+ Config: &TestConfig{Index: 3},
+ },
+ },
+ },
},
}
@@ -683,6 +721,8 @@ const (
keyTreeTests = "keyTreeTestskeyTreeTestskeyTreeTests"
clientAI = "client-ai"
keyAI = "clientaikeyclientaikeyclientaikey"
+ clientSkipStage = "client-skip-stage"
+ keySkipStage = "skipstagekeyskipstagekeyskipstagekey"
restrictedManager = "restricted-manager"
noFixBisectionManager = "no-fix-bisection-manager"
diff --git a/dashboard/app/reporting.go b/dashboard/app/reporting.go
index 61bee541d..ad55ac6c3 100644
--- a/dashboard/app/reporting.go
+++ b/dashboard/app/reporting.go
@@ -387,6 +387,14 @@ func (bug *Bug) managerConfig(c context.Context) *ConfigManager {
return &mgr
}
+func (bug *Bug) manuallyUpstreamed(name string) bool {
+ reporting := bugReportingByName(bug, name)
+ if reporting == nil {
+ return false
+ }
+ return !reporting.Closed.IsZero() && !reporting.Auto
+}
+
func createNotification(c context.Context, typ dashapi.BugNotif, public bool, text string, bug *Bug,
reporting *Reporting, bugReporting *BugReporting) (*dashapi.BugNotification, error) {
reportingConfig, err := json.Marshal(reporting.Config)
diff --git a/dashboard/app/reporting_test.go b/dashboard/app/reporting_test.go
index b1400c705..211797488 100644
--- a/dashboard/app/reporting_test.go
+++ b/dashboard/app/reporting_test.go
@@ -1417,3 +1417,53 @@ Blocks diff, Path
`, msg.Body)
}
+
+func TestSkipStage(t *testing.T) {
+ // The test ensures that manuallyUpstreamed works as intended in reporting filters.
+ c := NewCtx(t)
+ defer c.Close()
+ client := c.makeClient(clientSkipStage, keySkipStage, true)
+
+ build := testBuild(1)
+ client.UploadBuild(build)
+
+ {
+ // Normal scenario - manual upstreaming.
+ client.ReportCrash(testCrash(build, 1))
+ rep := client.pollBug()
+ c.expectEQ(string(rep.Config), `{"Index":1}`)
+ c.client.updateBug(rep.ID, dashapi.BugStatusUpstream, "")
+ client.pollNotifs(0)
+ rep = client.pollBug()
+ c.expectEQ(string(rep.Config), `{"Index":3}`)
+ c.client.updateBug(rep.ID, dashapi.BugStatusInvalid, "")
+ }
+
+ {
+ // Auto-upstreamed.
+ client.ReportCrash(testCrash(build, 2))
+ rep := client.pollBug()
+ c.expectEQ(string(rep.Config), `{"Index":1}`)
+ c.advanceTime(5 * 24 * time.Hour)
+ notifs := client.pollNotifs(1)
+ reply, _ := client.ReportingUpdate(&dashapi.BugUpdate{
+ ID: notifs[0].ID,
+ Status: dashapi.BugStatusUpstream,
+ Notification: true,
+ })
+ c.expectEQ(reply.OK, true)
+ rep = client.pollBug()
+ c.expectEQ(string(rep.Config), `{"Index":2}`)
+ c.client.updateBug(rep.ID, dashapi.BugStatusInvalid, "")
+ }
+
+ {
+ // Manually invalidated.
+ client.ReportCrash(testCrash(build, 3))
+ rep := client.pollBug()
+ c.expectEQ(string(rep.Config), `{"Index":1}`)
+ c.client.updateBug(rep.ID, dashapi.BugStatusInvalid, "")
+ client.pollNotifs(0)
+ client.pollBugs(0)
+ }
+}