Skip to content

Commit

Permalink
Allow template in pull request alert comment
Browse files Browse the repository at this point in the history
Ref #5120
  • Loading branch information
eleftherias committed Dec 12, 2024
1 parent b69d87d commit 3df29a0
Show file tree
Hide file tree
Showing 6 changed files with 1,638 additions and 1,568 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
enginerr "github.com/mindersec/minder/internal/engine/errors"
"github.com/mindersec/minder/internal/engine/interfaces"
pbinternal "github.com/mindersec/minder/internal/proto"
"github.com/mindersec/minder/internal/util"
pb "github.com/mindersec/minder/pkg/api/protobuf/go/minder/v1"
"github.com/mindersec/minder/pkg/profiles/models"
provifv1 "github.com/mindersec/minder/pkg/providers/v1"
Expand All @@ -30,6 +31,9 @@ import (
const (
// AlertType is the type of the pull request comment alert engine
AlertType = "pull_request_comment"
// PrCommentMaxLength is the maximum length of the pull request comment
// (this was derived from the limit of the GitHub API)
PrCommentMaxLength = 65536
)

// Alert is the structure backing the noop alert
Expand All @@ -40,11 +44,18 @@ type Alert struct {
setting models.ActionOpt
}

// PrCommentTemplateParams is the parameters for the PR comment templates
type PrCommentTemplateParams struct {
// EvalErrorDetails is the details of the error that occurred during evaluation, which may be empty
EvalErrorDetails string
}

type paramsPR struct {
Owner string
Repo string
CommitSha string
Number int
Comment string
Metadata *alertMetadata
prevStatus *db.ListRuleEvaluationsByProfileIdRow
}
Expand Down Expand Up @@ -102,7 +113,7 @@ func (alert *Alert) Do(
return nil, fmt.Errorf("expected repository, got %T", entity)
}

commentParams, err := getParamsForPRComment(ctx, pr, params, metadata)
commentParams, err := alert.getParamsForPRComment(ctx, pr, params, metadata)
if err != nil {
return nil, fmt.Errorf("error extracting parameters for PR comment: %w", err)
}
Expand All @@ -129,7 +140,7 @@ func (alert *Alert) run(ctx context.Context, params *paramsPR, cmd interfaces.Ac
review := &github.PullRequestReviewRequest{
CommitID: github.String(params.CommitSha),
Event: github.String("COMMENT"),
Body: github.String(alert.reviewCfg.ReviewMessage),
Body: github.String(params.Comment),
}

r, err := alert.gh.CreateReview(
Expand Down Expand Up @@ -196,7 +207,7 @@ func (alert *Alert) runDry(ctx context.Context, params *paramsPR, cmd interfaces
// Process the command
switch cmd {
case interfaces.ActionCmdOn:
body := github.String(alert.reviewCfg.ReviewMessage)
body := github.String(params.Comment)
logger.Info().Msgf("dry run: create a PR comment on PR %d in repo %s/%s with the following body: %s",
params.Number, params.Owner, params.Repo, *body)
return nil, nil
Expand Down Expand Up @@ -232,7 +243,7 @@ func (_ *Alert) runDoNothing(ctx context.Context, params *paramsPR) (json.RawMes
}

// getParamsForSecurityAdvisory extracts the details from the entity
func getParamsForPRComment(
func (alert *Alert) getParamsForPRComment(
ctx context.Context,
pr *pbinternal.PullRequest,
params interfaces.ActionsParams,
Expand All @@ -253,6 +264,22 @@ func getParamsForPRComment(
}
result.Number = int(pr.Number)

commentTmpl, err := util.NewSafeHTMLTemplate(&alert.reviewCfg.ReviewMessage, "message")
if err != nil {
return nil, fmt.Errorf("cannot parse review message template: %w", err)
}

tmplParams := &PrCommentTemplateParams{
EvalErrorDetails: enginerr.ErrorAsEvalDetails(params.GetEvalErr()),
}

comment, err := commentTmpl.Render(ctx, tmplParams, PrCommentMaxLength)
if err != nil {
return nil, fmt.Errorf("cannot execute title template: %w", err)
}

result.Comment = comment

// Unmarshal the existing alert metadata, if any
if metadata != nil {
meta := &alertMetadata{}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ import (

var TestActionTypeValid interfaces.ActionType = "alert-test"

const evaluationFailureDetails = "evaluation failure reason"

func TestPullRequestCommentAlert(t *testing.T) {
t.Parallel()

Expand All @@ -36,6 +38,7 @@ func TestPullRequestCommentAlert(t *testing.T) {
name string
actionType interfaces.ActionType
cmd interfaces.ActionCmd
reviewMsg string
inputMetadata *json.RawMessage
mockSetup func(*mockghclient.MockGitHub)
expectedErr error
Expand All @@ -44,6 +47,7 @@ func TestPullRequestCommentAlert(t *testing.T) {
{
name: "create a PR comment",
actionType: TestActionTypeValid,
reviewMsg: "This is a constant review message",
cmd: interfaces.ActionCmdOn,
mockSetup: func(mockGitHub *mockghclient.MockGitHub) {
mockGitHub.EXPECT().
Expand All @@ -52,9 +56,27 @@ func TestPullRequestCommentAlert(t *testing.T) {
},
expectedMetadata: json.RawMessage(fmt.Sprintf(`{"review_id":"%s"}`, reviewIDStr)),
},
{
name: "create a PR comment with template",
actionType: TestActionTypeValid,
reviewMsg: "{{ .EvalErrorDetails }}",
cmd: interfaces.ActionCmdOn,
mockSetup: func(mockGitHub *mockghclient.MockGitHub) {
mockGitHub.EXPECT().
CreateReview(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.AssignableToTypeOf(&github.PullRequestReviewRequest{})).
DoAndReturn(func(_ context.Context, _, _ string, _ int, review *github.PullRequestReviewRequest) (*github.PullRequestReview, error) {
if review.GetBody() != evaluationFailureDetails {
return nil, fmt.Errorf("expected review body to be %s, got %s", evaluationFailureDetails, review.GetBody())
}
return &github.PullRequestReview{ID: &reviewID}, nil
})
},
expectedMetadata: json.RawMessage(fmt.Sprintf(`{"review_id":"%s"}`, reviewIDStr)),
},
{
name: "error from provider creating PR comment",
actionType: TestActionTypeValid,
reviewMsg: "This is a constant review message",
cmd: interfaces.ActionCmdOn,
mockSetup: func(mockGitHub *mockghclient.MockGitHub) {
mockGitHub.EXPECT().
Expand All @@ -66,6 +88,7 @@ func TestPullRequestCommentAlert(t *testing.T) {
{
name: "dismiss PR comment",
actionType: TestActionTypeValid,
reviewMsg: "This is a constant review message",
cmd: interfaces.ActionCmdOff,
inputMetadata: &successfulRunMetadata,
mockSetup: func(mockGitHub *mockghclient.MockGitHub) {
Expand All @@ -89,7 +112,7 @@ func TestPullRequestCommentAlert(t *testing.T) {
})

prCommentCfg := pb.RuleType_Definition_Alert_AlertTypePRComment{
ReviewMessage: "This is a review message",
ReviewMessage: tt.reviewMsg,
}

mockClient := mockghclient.NewMockGitHub(ctrl)
Expand All @@ -105,6 +128,7 @@ func TestPullRequestCommentAlert(t *testing.T) {
Profile: &models.ProfileAggregate{},
Rule: &models.RuleInstance{},
}
evalParams.SetEvalErr(enginerr.NewErrEvaluationFailed(evaluationFailureDetails))

retMeta, err := prCommentAlert.Do(
context.Background(),
Expand Down
Loading

0 comments on commit 3df29a0

Please sign in to comment.