• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

go-playground / webhooks / 11185386857

04 Oct 2024 06:52PM UTC coverage: 88.583% (-0.4%) from 88.933%
11185386857

Pull #199

github

j2nullify
Autofix for finding 01J0HQ0A7GG1STVT9074R18TMZ
Pull Request #199: Autofix/01 j0 hq0 a7 gg1 stvt9074 r18 tmz

249 of 270 new or added lines in 9 files covered. (92.22%)

64 existing lines in 7 files now uncovered.

900 of 1016 relevant lines covered (88.58%)

8.77 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

87.61
/gitlab/gitlab.go
1
package gitlab
2

3
import (
4
        "crypto/sha512"
5
        "crypto/subtle"
6
        "encoding/json"
7
        "errors"
8
        "fmt"
9
        "io"
10
        "net/http"
11
)
12

13
// parse errors
14
var (
15
        ErrEventNotSpecifiedToParse      = errors.New("no Event specified to parse")
16
        ErrInvalidHTTPMethod             = errors.New("invalid HTTP Method")
17
        ErrMissingGitLabEventHeader      = errors.New("missing X-Gitlab-Event Header")
18
        ErrGitLabTokenVerificationFailed = errors.New("X-Gitlab-Token validation failed")
19
        ErrEventNotFound                 = errors.New("event not defined to be parsed")
20
        ErrParsingPayload                = errors.New("error parsing payload")
21
        ErrParsingSystemPayload          = errors.New("error parsing system payload")
22
        // ErrHMACVerificationFailed    = errors.New("HMAC verification failed")
23
)
24

25
// GitLab hook types
26
const (
27
        PushEvents                Event  = "Push Hook"
28
        TagEvents                 Event  = "Tag Push Hook"
29
        IssuesEvents              Event  = "Issue Hook"
30
        ConfidentialIssuesEvents  Event  = "Confidential Issue Hook"
31
        CommentEvents             Event  = "Note Hook"
32
        ConfidentialCommentEvents Event  = "Confidential Note Hook"
33
        MergeRequestEvents        Event  = "Merge Request Hook"
34
        WikiPageEvents            Event  = "Wiki Page Hook"
35
        PipelineEvents            Event  = "Pipeline Hook"
36
        BuildEvents               Event  = "Build Hook"
37
        JobEvents                 Event  = "Job Hook"
38
        DeploymentEvents          Event  = "Deployment Hook"
39
        ReleaseEvents             Event  = "Release Hook"
40
        SystemHookEvents          Event  = "System Hook"
41
        objectPush                string = "push"
42
        objectTag                 string = "tag_push"
43
        objectMergeRequest        string = "merge_request"
44
        objectBuild               string = "build"
45
        eventProjectCreate        string = "project_create"
46
        eventProjectDestroy       string = "project_destroy"
47
        eventProjectRename        string = "project_rename"
48
        eventProjectTransfer      string = "project_transfer"
49
        eventProjectUpdate        string = "project_update"
50
        eventUserAddToTeam        string = "user_add_to_team"
51
        eventUserRemoveFromTeam   string = "user_remove_from_team"
52
        eventUserUpdateForTeam    string = "user_update_for_team"
53
        eventUserCreate           string = "user_create"
54
        eventUserDestroy          string = "user_destroy"
55
        eventUserFailedLogin      string = "user_failed_login"
56
        eventUserRename           string = "user_rename"
57
        eventKeyCreate            string = "key_create"
58
        eventKeyDestroy           string = "key_destroy"
59
        eventGroupCreate          string = "group_create"
60
        eventGroupDestroy         string = "group_destroy"
61
        eventGroupRename          string = "group_rename"
62
        eventUserAddToGroup       string = "user_add_to_group"
63
        eventUserRemoveFromGroup  string = "user_remove_from_group"
64
        eventUserUpdateForGroup   string = "user_update_for_group"
65
)
66

67
// Option is a configuration option for the webhook
68
type Option func(*Webhook) error
69

70
// Options is a namespace var for configuration options
71
var Options = WebhookOptions{}
72

73
// WebhookOptions is a namespace for configuration option methods
74
type WebhookOptions struct{}
75

76
// Secret registers the GitLab secret
77
func (WebhookOptions) Secret(secret string) Option {
1✔
78
        return func(hook *Webhook) error {
2✔
79
                // already convert here to prevent timing attack (conversion depends on secret)
1✔
80
                hash := sha512.Sum512([]byte(secret))
1✔
81
                hook.secretHash = hash[:]
1✔
82
                return nil
1✔
83
        }
1✔
84
}
85

86
// Webhook instance contains all methods needed to process events
87
type Webhook struct {
88
        secretHash []byte
89
}
90

91
// Event defines a GitLab hook event type by the X-Gitlab-Event Header
92
type Event string
93

94
// New creates and returns a WebHook instance denoted by the Provider type
95
func New(options ...Option) (*Webhook, error) {
1✔
96
        hook := new(Webhook)
1✔
97
        for _, opt := range options {
2✔
98
                if err := opt(hook); err != nil {
1✔
UNCOV
99
                        return nil, errors.New("Error applying Option")
×
UNCOV
100
                }
×
101
        }
102
        return hook, nil
1✔
103
}
104

105
// Parse verifies and parses the events specified and returns the payload object or an error
106
func (hook Webhook) Parse(r *http.Request, events ...Event) (interface{}, error) {
43✔
107
        defer func() {
86✔
108
                _, _ = io.Copy(io.Discard, r.Body)
43✔
109
                _ = r.Body.Close()
43✔
110
        }()
43✔
111

112
        if len(events) == 0 {
43✔
UNCOV
113
                return nil, ErrEventNotSpecifiedToParse
×
UNCOV
114
        }
×
115
        if r.Method != http.MethodPost {
43✔
UNCOV
116
                return nil, ErrInvalidHTTPMethod
×
UNCOV
117
        }
×
118

119
        // If we have a Secret set, we should check in constant time
120
        if len(hook.secretHash) > 0 {
86✔
121
                tokenHash := sha512.Sum512([]byte(r.Header.Get("X-Gitlab-Token")))
43✔
122
                if subtle.ConstantTimeCompare(tokenHash[:], hook.secretHash[:]) == 0 {
46✔
123
                        return nil, ErrGitLabTokenVerificationFailed
3✔
124
                }
3✔
125
        }
126

127
        event := r.Header.Get("X-Gitlab-Event")
40✔
128
        if len(event) == 0 {
40✔
UNCOV
129
                return nil, ErrMissingGitLabEventHeader
×
UNCOV
130
        }
×
131

132
        gitLabEvent := Event(event)
40✔
133

40✔
134
        payload, err := io.ReadAll(r.Body)
40✔
135
        if err != nil || len(payload) == 0 {
41✔
136
                return nil, ErrParsingPayload
1✔
137
        }
1✔
138

139
        return eventParsing(gitLabEvent, events, payload)
39✔
140
}
141

142
func eventParsing(gitLabEvent Event, events []Event, payload []byte) (interface{}, error) {
43✔
143

43✔
144
        var found bool
43✔
145
        for _, evt := range events {
90✔
146
                if evt == gitLabEvent {
90✔
147
                        found = true
43✔
148
                        break
43✔
149
                }
150
        }
151
        // event not defined to be parsed
152
        if !found {
43✔
UNCOV
153
                return nil, ErrEventNotFound
×
154
        }
×
155

156
        switch gitLabEvent {
43✔
157
        case PushEvents:
2✔
158
                var pl PushEventPayload
2✔
159
                err := json.Unmarshal([]byte(payload), &pl)
2✔
160
                return pl, err
2✔
161

162
        case TagEvents:
2✔
163
                var pl TagEventPayload
2✔
164
                err := json.Unmarshal([]byte(payload), &pl)
2✔
165
                return pl, err
2✔
166

167
        case ConfidentialIssuesEvents:
1✔
168
                var pl ConfidentialIssueEventPayload
1✔
169
                err := json.Unmarshal([]byte(payload), &pl)
1✔
170
                return pl, err
1✔
171

172
        case IssuesEvents:
1✔
173
                var pl IssueEventPayload
1✔
174
                err := json.Unmarshal([]byte(payload), &pl)
1✔
175
                return pl, err
1✔
176

177
        case ConfidentialCommentEvents:
1✔
178
                var pl ConfidentialCommentEventPayload
1✔
179
                err := json.Unmarshal([]byte(payload), &pl)
1✔
180
                return pl, err
1✔
181

182
        case CommentEvents:
4✔
183
                var pl CommentEventPayload
4✔
184
                err := json.Unmarshal([]byte(payload), &pl)
4✔
185
                return pl, err
4✔
186

187
        case MergeRequestEvents:
2✔
188
                var pl MergeRequestEventPayload
2✔
189
                err := json.Unmarshal([]byte(payload), &pl)
2✔
190
                return pl, err
2✔
191

192
        case WikiPageEvents:
1✔
193
                var pl WikiPageEventPayload
1✔
194
                err := json.Unmarshal([]byte(payload), &pl)
1✔
195
                return pl, err
1✔
196

197
        case PipelineEvents:
1✔
198
                var pl PipelineEventPayload
1✔
199
                err := json.Unmarshal([]byte(payload), &pl)
1✔
200
                return pl, err
1✔
201

202
        case BuildEvents:
2✔
203
                var pl BuildEventPayload
2✔
204
                err := json.Unmarshal([]byte(payload), &pl)
2✔
205
                return pl, err
2✔
206

207
        case JobEvents:
1✔
208
                var pl JobEventPayload
1✔
209
                err := json.Unmarshal([]byte(payload), &pl)
1✔
210
                if err != nil {
1✔
UNCOV
211
                        return nil, err
×
UNCOV
212
                }
×
213
                if pl.ObjectKind == objectBuild {
2✔
214
                        return eventParsing(BuildEvents, events, payload)
1✔
215
                }
1✔
UNCOV
216
                return pl, nil
×
217

218
        case DeploymentEvents:
1✔
219
                var pl DeploymentEventPayload
1✔
220
                err := json.Unmarshal([]byte(payload), &pl)
1✔
221
                if err != nil {
1✔
NEW
222
                        return nil, err
×
NEW
223
                }
×
224
                return pl, nil
1✔
225

226
        case SystemHookEvents:
23✔
227
                var pl SystemHookPayload
23✔
228
                err := json.Unmarshal([]byte(payload), &pl)
23✔
229
                if err != nil {
23✔
UNCOV
230
                        return nil, err
×
UNCOV
231
                }
×
232

233
                switch pl.ObjectKind {
23✔
UNCOV
234
                case objectPush:
×
UNCOV
235
                        return eventParsing(PushEvents, events, payload)
×
236

UNCOV
237
                case objectTag:
×
UNCOV
238
                        return eventParsing(TagEvents, events, payload)
×
239

240
                case objectMergeRequest:
1✔
241
                        return eventParsing(MergeRequestEvents, events, payload)
1✔
242
                default:
22✔
243
                        switch pl.EventName {
22✔
244
                        case objectPush:
1✔
245
                                return eventParsing(PushEvents, events, payload)
1✔
246

247
                        case objectTag:
1✔
248
                                return eventParsing(TagEvents, events, payload)
1✔
249

UNCOV
250
                        case objectMergeRequest:
×
UNCOV
251
                                return eventParsing(MergeRequestEvents, events, payload)
×
252

253
                        case eventProjectCreate:
1✔
254
                                var pl ProjectCreatedEventPayload
1✔
255
                                err := json.Unmarshal([]byte(payload), &pl)
1✔
256
                                return pl, err
1✔
257

258
                        case eventProjectDestroy:
1✔
259
                                var pl ProjectDestroyedEventPayload
1✔
260
                                err := json.Unmarshal([]byte(payload), &pl)
1✔
261
                                return pl, err
1✔
262

263
                        case eventProjectRename:
1✔
264
                                var pl ProjectRenamedEventPayload
1✔
265
                                err := json.Unmarshal([]byte(payload), &pl)
1✔
266
                                return pl, err
1✔
267

268
                        case eventProjectTransfer:
1✔
269
                                var pl ProjectTransferredEventPayload
1✔
270
                                err := json.Unmarshal([]byte(payload), &pl)
1✔
271
                                return pl, err
1✔
272

273
                        case eventProjectUpdate:
1✔
274
                                var pl ProjectUpdatedEventPayload
1✔
275
                                err := json.Unmarshal([]byte(payload), &pl)
1✔
276
                                return pl, err
1✔
277

278
                        case eventUserAddToTeam:
1✔
279
                                var pl TeamMemberAddedEventPayload
1✔
280
                                err := json.Unmarshal([]byte(payload), &pl)
1✔
281
                                return pl, err
1✔
282

283
                        case eventUserRemoveFromTeam:
1✔
284
                                var pl TeamMemberRemovedEventPayload
1✔
285
                                err := json.Unmarshal([]byte(payload), &pl)
1✔
286
                                return pl, err
1✔
287

288
                        case eventUserUpdateForTeam:
1✔
289
                                var pl TeamMemberUpdatedEventPayload
1✔
290
                                err := json.Unmarshal([]byte(payload), &pl)
1✔
291
                                return pl, err
1✔
292

293
                        case eventUserCreate:
1✔
294
                                var pl UserCreatedEventPayload
1✔
295
                                err := json.Unmarshal([]byte(payload), &pl)
1✔
296
                                return pl, err
1✔
297

298
                        case eventUserDestroy:
1✔
299
                                var pl UserRemovedEventPayload
1✔
300
                                err := json.Unmarshal([]byte(payload), &pl)
1✔
301
                                return pl, err
1✔
302

303
                        case eventUserFailedLogin:
1✔
304
                                var pl UserFailedLoginEventPayload
1✔
305
                                err := json.Unmarshal([]byte(payload), &pl)
1✔
306
                                return pl, err
1✔
307

308
                        case eventUserRename:
1✔
309
                                var pl UserRenamedEventPayload
1✔
310
                                err := json.Unmarshal([]byte(payload), &pl)
1✔
311
                                return pl, err
1✔
312

313
                        case eventKeyCreate:
1✔
314
                                var pl KeyAddedEventPayload
1✔
315
                                err := json.Unmarshal([]byte(payload), &pl)
1✔
316
                                return pl, err
1✔
317

318
                        case eventKeyDestroy:
1✔
319
                                var pl KeyRemovedEventPayload
1✔
320
                                err := json.Unmarshal([]byte(payload), &pl)
1✔
321
                                return pl, err
1✔
322

323
                        case eventGroupCreate:
1✔
324
                                var pl GroupCreatedEventPayload
1✔
325
                                err := json.Unmarshal([]byte(payload), &pl)
1✔
326
                                return pl, err
1✔
327

328
                        case eventGroupDestroy:
1✔
329
                                var pl GroupRemovedEventPayload
1✔
330
                                err := json.Unmarshal([]byte(payload), &pl)
1✔
331
                                return pl, err
1✔
332

333
                        case eventGroupRename:
1✔
334
                                var pl GroupRenamedEventPayload
1✔
335
                                err := json.Unmarshal([]byte(payload), &pl)
1✔
336
                                return pl, err
1✔
337

338
                        case eventUserAddToGroup:
1✔
339
                                var pl GroupMemberAddedEventPayload
1✔
340
                                err := json.Unmarshal([]byte(payload), &pl)
1✔
341
                                return pl, err
1✔
342

343
                        case eventUserRemoveFromGroup:
1✔
344
                                var pl GroupMemberRemovedEventPayload
1✔
345
                                err := json.Unmarshal([]byte(payload), &pl)
1✔
346
                                return pl, err
1✔
347

348
                        case eventUserUpdateForGroup:
1✔
349
                                var pl GroupMemberUpdatedEventPayload
1✔
350
                                err := json.Unmarshal([]byte(payload), &pl)
1✔
351
                                return pl, err
1✔
352

UNCOV
353
                        default:
×
UNCOV
354
                                return nil, fmt.Errorf("unknown system hook event %s", gitLabEvent)
×
355
                        }
356
                }
357
        case ReleaseEvents:
1✔
358
                var pl ReleaseEventPayload
1✔
359
                err := json.Unmarshal([]byte(payload), &pl)
1✔
360
                return pl, err
1✔
UNCOV
361
        default:
×
UNCOV
362
                return nil, fmt.Errorf("unknown event %s", gitLabEvent)
×
363
        }
364
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc