github.com/google/syzkaller@v0.0.0-20251211124644-a066d2bc4b02/syz-cluster/email-reporter/main.go (about) 1 // Copyright 2025 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 // NOTE: This app assumes that only one copy of it is runnning at the same time. 5 6 package main 7 8 import ( 9 "context" 10 "log" 11 "time" 12 13 "github.com/google/syzkaller/pkg/email/lore" 14 "github.com/google/syzkaller/syz-cluster/pkg/api" 15 "github.com/google/syzkaller/syz-cluster/pkg/app" 16 "github.com/google/syzkaller/syz-cluster/pkg/emailclient" 17 "golang.org/x/sync/errgroup" 18 ) 19 20 // TODO: add extra sanity checks that would prevent flooding the mailing lists: 21 // - this pod may crash and be restarted by K8S: this complicates accounting, 22 // - the send operation might return an error, yet an email would be actually sent: back off on errors? 23 24 const ( 25 // How often to check whether there are new emails to be sent. 26 senderPollPeriod = 30 * time.Second 27 // How often to check whether there are new incoming emails. 28 fetcherPollPeriod = 2 * time.Minute 29 ) 30 31 func main() { 32 ctx := context.Background() 33 cfg, err := app.Config() 34 if err != nil { 35 app.Fatalf("failed to load config: %v", err) 36 } 37 if cfg.EmailReporting == nil { 38 app.Fatalf("reporting is not configured: %v", err) 39 } 40 sender, err := emailclient.MakeSender(ctx, cfg.EmailReporting) 41 if err != nil { 42 app.Fatalf("failed to create a sender: %s", err) 43 } 44 reporterClient := app.DefaultReporterClient() 45 handler := &Handler{ 46 reporter: api.LKMLReporter, 47 apiClient: reporterClient, 48 emailConfig: cfg.EmailReporting, 49 sender: sender, 50 } 51 msgCh := make(chan *lore.Email, 16) 52 eg, loopCtx := errgroup.WithContext(ctx) 53 if cfg.EmailReporting.LoreArchiveURL != "" { 54 fetcher := NewLKMLEmailStream("/lore-repo/checkout", reporterClient, cfg.EmailReporting, msgCh) 55 eg.Go(func() error { return fetcher.Loop(loopCtx, fetcherPollPeriod) }) 56 } 57 eg.Go(func() error { 58 for { 59 var newEmail *lore.Email 60 select { 61 case newEmail = <-msgCh: 62 case <-loopCtx.Done(): 63 return nil 64 } 65 log.Printf("received email %q", newEmail.MessageID) 66 err := handler.IncomingEmail(loopCtx, newEmail.Email) 67 if err != nil { 68 // Note that we just print an error and go on instead of retrying. 69 // Some retrying may be reasonable, but it also comes with a risk of flooding 70 // the mailing lists. 71 app.Errorf("email %q: failed to process: %v", newEmail.MessageID, err) 72 } 73 } 74 }) 75 eg.Go(func() error { 76 handler.PollReportsLoop(loopCtx, senderPollPeriod) 77 return nil 78 }) 79 if err = eg.Wait(); err != nil { 80 app.Errorf("failed: %s", err) 81 } 82 }