From 3b79d489db1ad98df7f1986a4695f581e6be9be3 Mon Sep 17 00:00:00 2001 From: Aleksandr Nogikh Date: Tue, 18 Feb 2025 18:13:35 +0100 Subject: syz-cluster/series-tracker: collect Cc addresses Extract Cc addresses for the processed patch series. --- syz-cluster/series-tracker/main.go | 38 ++++++++++++++++++++++++++-- syz-cluster/series-tracker/main_test.go | 45 +++++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+), 2 deletions(-) create mode 100644 syz-cluster/series-tracker/main_test.go diff --git a/syz-cluster/series-tracker/main.go b/syz-cluster/series-tracker/main.go index 6a0379fc2..a9de34a31 100644 --- a/syz-cluster/series-tracker/main.go +++ b/syz-cluster/series-tracker/main.go @@ -4,12 +4,17 @@ package main import ( + "bytes" "context" + "errors" "flag" "fmt" "log" + "maps" "path/filepath" "regexp" + "slices" + "sort" "time" "github.com/google/syzkaller/pkg/email" @@ -141,11 +146,18 @@ func (sf *SeriesFetcher) handleSeries(ctx context.Context, series *lore.Series, Link: "https://lore.kernel.org/all/" + series.MessageID, PublishedAt: date, } - for _, patch := range series.Patches { - body, err := idToReader[patch.MessageID].Read() + sp := seriesProcessor{} + for i, patch := range series.Patches { + raw, err := idToReader[patch.MessageID].Read() if err != nil { return fmt.Errorf("failed to extract %q: %w", patch.MessageID, err) } + body, err := sp.Process(raw) + if err != nil { + // Fall back to the raw message. + body = raw + log.Printf("failed to parse %d: %v", i, err) + } apiSeries.Patches = append(apiSeries.Patches, api.SeriesPatch{ Seq: patch.Seq, Title: patch.Subject, @@ -153,6 +165,7 @@ func (sf *SeriesFetcher) handleSeries(ctx context.Context, series *lore.Series, Body: body, }) } + apiSeries.Cc = sp.Emails() ret, err := sf.client.UploadSeries(ctx, apiSeries) if err != nil { return fmt.Errorf("failed to save series: %w", err) @@ -170,6 +183,27 @@ func (sf *SeriesFetcher) handleSeries(ctx context.Context, series *lore.Series, return nil } +type seriesProcessor map[string]struct{} + +var errFailedToParse = errors.New("failed to parse the email") + +func (sp seriesProcessor) Process(raw []byte) ([]byte, error) { + msg, err := email.Parse(bytes.NewReader(raw), nil, nil, nil) + if err != nil { + return raw, fmt.Errorf("%w: %w", errFailedToParse, err) + } + for _, email := range msg.Cc { + sp[email] = struct{}{} + } + return []byte(msg.Body), nil +} + +func (sp seriesProcessor) Emails() []string { + list := slices.Collect(maps.Keys(sp)) + sort.Strings(list) + return list +} + func logSeries(series *lore.Series) { log.Printf("series ID=%s Subject=%s Patches=%d Version=%d Corrupted=%q", series.MessageID, series.Subject, len(series.Patches), series.Version, diff --git a/syz-cluster/series-tracker/main_test.go b/syz-cluster/series-tracker/main_test.go new file mode 100644 index 000000000..805335076 --- /dev/null +++ b/syz-cluster/series-tracker/main_test.go @@ -0,0 +1,45 @@ +// 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 main + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestSeriesProcessor(t *testing.T) { + emails := []string{ + `Date: Sun, 7 May 2017 19:54:00 -0700 +Message-ID: <123> +Subject: test subject +From: Bob +To: A +Cc: B , C + +first body`, + `Date: Sun, 7 May 2017 19:55:00 -0700 +Message-ID: <234> +Subject: test subject2 +From: Bob +To: A +Cc: D + +second body`, + } + bodies := []string{"first body", "second body"} + + sp := seriesProcessor{} + for i, raw := range emails { + body, err := sp.Process([]byte(raw)) + if err != nil { + t.Fatal(err) + } + assert.Equal(t, []byte(bodies[i]), body) + } + assert.Equal(t, []string{ + "a@a.com", "b@b.com", + "bob@example.com", "d@d.com", + }, sp.Emails()) +} -- cgit mrf-deployment