blob: 25db6a19c782151a74b5647fc1bde99d4c8cf433 [file] [log] [blame]
// Copyright 2024 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package task
import (
"context"
"net/mail"
"os"
"path/filepath"
"reflect"
"strings"
"testing"
"time"
"golang.org/x/build/gerrit"
"golang.org/x/build/internal/workflow"
)
type privxClient struct {
GerritClient
privRepoDir string
}
func (c *privxClient) Submitted(ctx context.Context, changeID string, parentCommit string) (string, bool, error) {
return "123", true, nil
}
func (c *privxClient) ListProjects(ctx context.Context) ([]string, error) {
return []string{"net"}, nil
}
func (c *privxClient) ReadBranchHead(ctx context.Context, project string, branch string) (string, error) {
return "", nil
}
func (c *privxClient) ReadFile(ctx context.Context, project string, head string, file string) ([]byte, error) {
return []byte("module golang.org/x/net\n\ngo 1.24"), nil
}
func (c *privxClient) ListTags(ctx context.Context, repo string) ([]string, error) {
return []string{"v1.0.0"}, nil
}
func (c *privxClient) Tag(ctx context.Context, repo string, tag string, commit string) error {
return nil
}
func (c *privxClient) GetChange(ctx context.Context, changeID string, opts ...gerrit.QueryChangesOpt) (*gerrit.ChangeInfo, error) {
return &gerrit.ChangeInfo{
Project: "net",
Status: gerrit.ChangeStatusMerged,
CurrentRevision: "dead",
Revisions: map[string]gerrit.RevisionInfo{
"dead": {
Fetch: map[string]*gerrit.FetchInfo{
"http": {
URL: c.privRepoDir,
Ref: "refs/changes/1234/5",
},
},
},
},
}, nil
}
func TestPrivXPatch(t *testing.T) {
privRepo := NewFakeRepo(t, "net")
pubRepo := NewFakeRepo(t, "net")
privCommit := privRepo.CommitOnBranch("master", map[string]string{"hi.go": ":)"})
privRepo.runGit("update-ref", "refs/changes/1234/5", privCommit)
if err := os.WriteFile(filepath.Join(pubRepo.dir.dir, ".git/hooks/pre-receive"), []byte(`#!/bin/sh
echo "Resolving deltas: 100% (5/5)"
echo "Waiting for private key checker: 1/1 objects left"
echo "Processing changes: refs: 1, new: 1, done"
echo
echo "SUCCESS"
echo
echo " https://go-review.googlesource.com/c/net/+/558675 net/mail: remove obsolete comment [NEW]"
echo`), 0777); err != nil {
t.Fatalf("failed to write git pre-receive hook: %s", err)
}
pubBase, _ := strings.CutSuffix(pubRepo.dir.dir, filepath.Base(pubRepo.dir.dir))
var announcementHeader MailHeader
var announcementMessage MailContent
p := &PrivXPatch{
Git: &Git{},
PrivateGerrit: &privxClient{privRepoDir: privRepo.dir.dir},
PublicGerrit: &privxClient{},
PublicRepoURL: func(repo string) string {
return pubBase + "/" + repo
},
ApproveAction: func(*workflow.TaskContext) error { return nil },
SendMail: func(mh MailHeader, mc MailContent) error {
announcementHeader, announcementMessage = mh, mc
return nil
},
AnnounceMailHeader: MailHeader{
From: mail.Address{Address: "hello@google.com"},
To: mail.Address{Address: "there@google.com"},
},
}
wd := p.NewDefinition(&TagXReposTasks{Gerrit: &privxClient{}})
w, err := workflow.Start(wd, map[string]any{
"go-internal CL number": "1234",
"Reviewer usernames (optional)": []string{},
"Repository name": filepath.Base(pubRepo.dir.dir),
"Skip post submit result (optional)": true,
"CVE": "CVE-2024-1234",
"GitHub issue": "https://go.dev/issues/1234",
"Release note": "We fixed a thing.",
"Acknowledgement": "a very nice person",
})
if err != nil {
t.Fatal(err)
}
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
defer cancel()
_, err = w.Run(ctx, &verboseListener{t: t})
if err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(announcementHeader, p.AnnounceMailHeader) {
t.Errorf("unexpected announcement header: got %#v, want %#v", announcementHeader, p.AnnounceMailHeader)
}
expectedSubject := `[security] Vulnerability in golang.org/x/net`
if announcementMessage.Subject != expectedSubject {
t.Errorf("unexpected announcement subject: got %q, want %q", announcementMessage.Subject, expectedSubject)
}
expectedMessage := `Hello gophers,
We have tagged version v1.1.0 of golang.org/x/net in order to address a security issue.
We fixed a thing.
Thanks to a very nice person for reporting this issue.
This is CVE-2024-1234 and Go issue https://go.dev/issues/1234.
Cheers,
Go Security team
`
if announcementMessage.BodyText != expectedMessage {
t.Errorf("unexpected announcement plaintext: got: %s\n\nwant: %s\n", announcementMessage.BodyText, expectedMessage)
}
expectedHTML := `<p>Hello gophers,</p>
<p>We have tagged version v1.1.0 of golang.org/x/net in order to address a security issue.</p>
<p>We fixed a thing.</p>
<p>Thanks to a very nice person for reporting this issue.</p>
<p>This is CVE-2024-1234 and Go issue <a href="https://go.dev/issues/1234">https://go.dev/issues/1234</a>.</p>
<p>Cheers,<br>
Go Security team</p>
`
if announcementMessage.BodyHTML != expectedHTML {
t.Errorf("unexpected announcement HTML: got: %s\n\nwant: %s\n", announcementMessage.BodyHTML, expectedHTML)
}
}