@@ -10,11 +10,8 @@ import (
10
10
"encoding/json"
11
11
"errors"
12
12
"fmt"
13
- "math"
14
- "strconv"
15
- "time"
16
-
17
13
"github.com/google/go-github/v63/github"
14
+ "github.com/mindersec/minder/internal/entities/properties"
18
15
"github.com/rs/zerolog"
19
16
"google.golang.org/protobuf/reflect/protoreflect"
20
17
@@ -39,7 +36,7 @@ const (
39
36
// Alert is the structure backing the noop alert
40
37
type Alert struct {
41
38
actionType interfaces.ActionType
42
- gh provifv1.GitHub
39
+ commenter provifv1.PullRequestCommenter
43
40
reviewCfg * pb.RuleType_Definition_Alert_AlertTypePRComment
44
41
setting models.ActionOpt
45
42
}
@@ -54,26 +51,17 @@ type PrCommentTemplateParams struct {
54
51
}
55
52
56
53
type paramsPR struct {
57
- Owner string
58
- Repo string
59
- CommitSha string
60
- Number int
61
54
Comment string
62
- Metadata * alertMetadata
55
+ props * properties.Properties
56
+ Metadata * provifv1.CommentResultMeta
63
57
prevStatus * db.ListRuleEvaluationsByProfileIdRow
64
58
}
65
59
66
- type alertMetadata struct {
67
- ReviewID string `json:"review_id,omitempty"`
68
- SubmittedAt * time.Time `json:"submitted_at,omitempty"`
69
- PullRequestUrl * string `json:"pull_request_url,omitempty"`
70
- }
71
-
72
60
// NewPullRequestCommentAlert creates a new pull request comment alert action
73
61
func NewPullRequestCommentAlert (
74
62
actionType interfaces.ActionType ,
75
63
reviewCfg * pb.RuleType_Definition_Alert_AlertTypePRComment ,
76
- gh provifv1.GitHub ,
64
+ gh provifv1.PullRequestCommenter ,
77
65
setting models.ActionOpt ,
78
66
) (* Alert , error ) {
79
67
if actionType == "" {
@@ -82,7 +70,7 @@ func NewPullRequestCommentAlert(
82
70
83
71
return & Alert {
84
72
actionType : actionType ,
85
- gh : gh ,
73
+ commenter : gh ,
86
74
reviewCfg : reviewCfg ,
87
75
setting : setting ,
88
76
}, nil
@@ -134,68 +122,14 @@ func (alert *Alert) Do(
134
122
}
135
123
136
124
func (alert * Alert ) run (ctx context.Context , params * paramsPR , cmd interfaces.ActionCmd ) (json.RawMessage , error ) {
137
- logger := zerolog .Ctx (ctx )
138
-
139
125
// Process the command
140
126
switch cmd {
141
- // Create a review
142
127
case interfaces .ActionCmdOn :
143
- review := & github.PullRequestReviewRequest {
144
- CommitID : github .String (params .CommitSha ),
145
- Event : github .String ("COMMENT" ),
146
- Body : github .String (params .Comment ),
147
- }
148
-
149
- r , err := alert .gh .CreateReview (
150
- ctx ,
151
- params .Owner ,
152
- params .Repo ,
153
- params .Number ,
154
- review ,
155
- )
156
- if err != nil {
157
- return nil , fmt .Errorf ("error creating PR review: %w, %w" , err , enginerr .ErrActionFailed )
158
- }
159
-
160
- newMeta , err := json .Marshal (alertMetadata {
161
- ReviewID : strconv .FormatInt (r .GetID (), 10 ),
162
- SubmittedAt : r .SubmittedAt .GetTime (),
163
- PullRequestUrl : r .PullRequestURL ,
164
- })
165
- if err != nil {
166
- return nil , fmt .Errorf ("error marshalling alert metadata json: %w" , err )
167
- }
168
-
169
- logger .Info ().Int64 ("review_id" , * r .ID ).Msg ("PR review created" )
170
- return newMeta , nil
171
- // Dismiss the review
128
+ // Create a review
129
+ return alert .runDoReview (ctx , params )
172
130
case interfaces .ActionCmdOff :
173
- if params .Metadata == nil {
174
- // We cannot do anything without the PR review ID, so we assume that turning the alert off is a success
175
- return nil , fmt .Errorf ("no PR comment ID provided: %w" , enginerr .ErrActionTurnedOff )
176
- }
177
-
178
- reviewID , err := strconv .ParseInt (params .Metadata .ReviewID , 10 , 64 )
179
- if err != nil {
180
- zerolog .Ctx (ctx ).Error ().Err (err ).Str ("review_id" , params .Metadata .ReviewID ).Msg ("failed to parse review_id" )
181
- return nil , fmt .Errorf ("no PR comment ID provided: %w, %w" , err , enginerr .ErrActionTurnedOff )
182
- }
183
-
184
- _ , err = alert .gh .DismissReview (ctx , params .Owner , params .Repo , params .Number , reviewID ,
185
- & github.PullRequestReviewDismissalRequest {
186
- Message : github .String ("Dismissed due to alert being turned off" ),
187
- })
188
- if err != nil {
189
- if errors .Is (err , enginerr .ErrNotFound ) {
190
- // There's no PR review with that ID anymore.
191
- // We exit by stating that the action was turned off.
192
- return nil , fmt .Errorf ("PR comment already dismissed: %w, %w" , err , enginerr .ErrActionTurnedOff )
193
- }
194
- return nil , fmt .Errorf ("error dismissing PR comment: %w, %w" , err , enginerr .ErrActionFailed )
195
- }
196
- logger .Info ().Str ("review_id" , params .Metadata .ReviewID ).Msg ("PR comment dismissed" )
197
- // Success - return ErrActionTurnedOff to indicate the action was successful
198
- return nil , fmt .Errorf ("%s : %w" , alert .Class (), enginerr .ErrActionTurnedOff )
131
+ // Dismiss the review
132
+ return runDismissReview (ctx , alert , params )
199
133
case interfaces .ActionCmdDoNothing :
200
134
// Return the previous alert status.
201
135
return alert .runDoNothing (ctx , params )
@@ -211,16 +145,16 @@ func (alert *Alert) runDry(ctx context.Context, params *paramsPR, cmd interfaces
211
145
switch cmd {
212
146
case interfaces .ActionCmdOn :
213
147
body := github .String (params .Comment )
214
- logger .Info ().Msgf ( "dry run: create a PR comment on PR %d in repo %s/%s with the following body: %s" ,
215
- params . Number , params . Owner , params . Repo , * body )
148
+ logger .Info ().Dict ( "properties" , params . props . ToLogDict ()).
149
+ Msgf ( "dry run: create a PR comment on PR with body: %s" , * body )
216
150
return nil , nil
217
151
case interfaces .ActionCmdOff :
218
152
if params .Metadata == nil {
219
153
// We cannot do anything without the PR review ID, so we assume that turning the alert off is a success
220
154
return nil , fmt .Errorf ("no PR comment ID provided: %w" , enginerr .ErrActionTurnedOff )
221
155
}
222
- logger .Info ().Msgf ( "dry run: dismiss PR comment %s on PR PR %d in repo %s/%s " , params .Metadata . ReviewID ,
223
- params . Number , params . Owner , params . Repo )
156
+ logger .Info ().Dict ( "properties " , params .props . ToLogDict ()).
157
+ Msgf ( "dry run: dismiss PR comment on PR" )
224
158
case interfaces .ActionCmdDoNothing :
225
159
// Return the previous alert status.
226
160
return alert .runDoNothing (ctx , params )
@@ -231,7 +165,7 @@ func (alert *Alert) runDry(ctx context.Context, params *paramsPR, cmd interfaces
231
165
232
166
// runDoNothing returns the previous alert status
233
167
func (_ * Alert ) runDoNothing (ctx context.Context , params * paramsPR ) (json.RawMessage , error ) {
234
- logger := zerolog .Ctx (ctx ).With ().Str ( "repo " , params .Repo ).Logger ()
168
+ logger := zerolog .Ctx (ctx ).With ().Dict ( "properties " , params .props . ToLogDict () ).Logger ()
235
169
236
170
logger .Debug ().Msg ("Running do nothing" )
237
171
@@ -245,6 +179,49 @@ func (_ *Alert) runDoNothing(ctx context.Context, params *paramsPR) (json.RawMes
245
179
return nil , err
246
180
}
247
181
182
+ func (alert * Alert ) runDoReview (ctx context.Context , params * paramsPR ) (json.RawMessage , error ) {
183
+ logger := zerolog .Ctx (ctx )
184
+
185
+ r , err := alert .commenter .CommentOnPullRequest (ctx , params .props , provifv1.PullRequestCommentInfo {
186
+ // TODO: We should add the header to identify the alert. We could use the
187
+ // rule type name.
188
+ Commit : params .props .GetProperty (properties .PullRequestCommitSHA ).GetString (),
189
+ Body : params .Comment ,
190
+ // TODO: Determine the priority from the rule type severity
191
+ })
192
+ if err != nil {
193
+ return nil , fmt .Errorf ("error creating PR review: %w, %w" , err , enginerr .ErrActionFailed )
194
+ }
195
+ logger .Info ().Str ("review_id" , r .ID ).Msg ("PR review created" )
196
+
197
+ // serialize r to json
198
+ meta , err := json .Marshal (r )
199
+ if err != nil {
200
+ return nil , fmt .Errorf ("error marshalling PR review metadata: %w" , err )
201
+ }
202
+
203
+ return meta , nil
204
+ }
205
+
206
+ func runDismissReview (ctx context.Context , alert * Alert , params * paramsPR ) (json.RawMessage , error ) {
207
+ if params .Metadata == nil {
208
+ // We cannot do anything without the PR review ID, so we assume that turning the alert off is a success
209
+ return nil , fmt .Errorf ("no PR comment ID provided: %w" , enginerr .ErrActionTurnedOff )
210
+ }
211
+
212
+ err := alert .commenter .DismissPullRequestReview (ctx , params .props )
213
+ if err != nil {
214
+ if errors .Is (err , enginerr .ErrNotFound ) {
215
+ // There's no PR review with that ID anymore.
216
+ // We exit by stating that the action was turned off.
217
+ return nil , fmt .Errorf ("PR comment already dismissed: %w, %w" , err , enginerr .ErrActionTurnedOff )
218
+ }
219
+ return nil , fmt .Errorf ("error dismissing PR comment: %w, %w" , err , enginerr .ErrActionFailed )
220
+ }
221
+ // Success - return ErrActionTurnedOff to indicate the action was successful
222
+ return nil , fmt .Errorf ("%s : %w" , alert .Class (), enginerr .ErrActionTurnedOff )
223
+ }
224
+
248
225
// getParamsForSecurityAdvisory extracts the details from the entity
249
226
func (alert * Alert ) getParamsForPRComment (
250
227
ctx context.Context ,
@@ -253,19 +230,15 @@ func (alert *Alert) getParamsForPRComment(
253
230
metadata * json.RawMessage ,
254
231
) (* paramsPR , error ) {
255
232
logger := zerolog .Ctx (ctx )
256
- result := & paramsPR {
257
- prevStatus : params .GetEvalStatusFromDb (),
258
- Owner : pr .GetRepoOwner (),
259
- Repo : pr .GetRepoName (),
260
- CommitSha : pr .GetCommitSha (),
233
+ props , err := properties .NewProperties (pr .GetProperties ().AsMap ())
234
+ if err != nil {
235
+ return nil , fmt .Errorf ("error creating properties: %w" , err )
261
236
}
262
237
263
- // The GitHub Go API takes an int32, but our proto stores an int64; make sure we don't overflow
264
- // The PR number is an int in GitHub and Gitlab; in practice overflow will never happen.
265
- if pr .Number > math .MaxInt {
266
- return nil , fmt .Errorf ("pr number is too large" )
238
+ result := & paramsPR {
239
+ prevStatus : params .GetEvalStatusFromDb (),
240
+ props : props ,
267
241
}
268
- result .Number = int (pr .Number )
269
242
270
243
commentTmpl , err := util .NewSafeHTMLTemplate (& alert .reviewCfg .ReviewMessage , "message" )
271
244
if err != nil {
@@ -289,7 +262,7 @@ func (alert *Alert) getParamsForPRComment(
289
262
290
263
// Unmarshal the existing alert metadata, if any
291
264
if metadata != nil {
292
- meta := & alertMetadata {}
265
+ meta := & provifv1. CommentResultMeta {}
293
266
err := json .Unmarshal (* metadata , meta )
294
267
if err != nil {
295
268
// There's nothing saved apparently, so no need to fail here, but do log the error
0 commit comments