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

go-playground / webhooks / 15063965098

16 May 2025 08:17AM CUT coverage: 88.933%. Remained the same
15063965098

Pull #208

github

Kinga Sieminiak
Fix json tag
Pull Request #208: Extend GitHub changes payload

900 of 1012 relevant lines covered (88.93%)

8.8 hits per line

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

94.96
/github/github.go
1
package github
2

3
import (
4
        "crypto/hmac"
5
        "crypto/sha1"
6
        "encoding/hex"
7
        "encoding/json"
8
        "errors"
9
        "fmt"
10
        "io"
11
        "io/ioutil"
12
        "net/http"
13
)
14

15
// parse errors
16
var (
17
        ErrEventNotSpecifiedToParse  = errors.New("no Event specified to parse")
18
        ErrInvalidHTTPMethod         = errors.New("invalid HTTP Method")
19
        ErrMissingGithubEventHeader  = errors.New("missing X-GitHub-Event Header")
20
        ErrMissingHubSignatureHeader = errors.New("missing X-Hub-Signature Header")
21
        ErrEventNotFound             = errors.New("event not defined to be parsed")
22
        ErrParsingPayload            = errors.New("error parsing payload")
23
        ErrHMACVerificationFailed    = errors.New("HMAC verification failed")
24
)
25

26
// Event defines a GitHub hook event type
27
type Event string
28

29
// GitHub hook types
30
const (
31
        CheckRunEvent                            Event = "check_run"
32
        CheckSuiteEvent                          Event = "check_suite"
33
        CommitCommentEvent                       Event = "commit_comment"
34
        CreateEvent                              Event = "create"
35
        DeleteEvent                              Event = "delete"
36
        DeploymentEvent                          Event = "deployment"
37
        DeploymentStatusEvent                    Event = "deployment_status"
38
        ForkEvent                                Event = "fork"
39
        GollumEvent                              Event = "gollum"
40
        InstallationEvent                        Event = "installation"
41
        InstallationRepositoriesEvent            Event = "installation_repositories"
42
        IntegrationInstallationEvent             Event = "integration_installation"
43
        IntegrationInstallationRepositoriesEvent Event = "integration_installation_repositories"
44
        IssueCommentEvent                        Event = "issue_comment"
45
        IssuesEvent                              Event = "issues"
46
        LabelEvent                               Event = "label"
47
        MemberEvent                              Event = "member"
48
        MembershipEvent                          Event = "membership"
49
        MilestoneEvent                           Event = "milestone"
50
        MetaEvent                                Event = "meta"
51
        OrganizationEvent                        Event = "organization"
52
        OrgBlockEvent                            Event = "org_block"
53
        PageBuildEvent                           Event = "page_build"
54
        PingEvent                                Event = "ping"
55
        ProjectCardEvent                         Event = "project_card"
56
        ProjectColumnEvent                       Event = "project_column"
57
        ProjectEvent                             Event = "project"
58
        PublicEvent                              Event = "public"
59
        PullRequestEvent                         Event = "pull_request"
60
        PullRequestReviewEvent                   Event = "pull_request_review"
61
        PullRequestReviewCommentEvent            Event = "pull_request_review_comment"
62
        PushEvent                                Event = "push"
63
        ReleaseEvent                             Event = "release"
64
        RepositoryEvent                          Event = "repository"
65
        RepositoryVulnerabilityAlertEvent        Event = "repository_vulnerability_alert"
66
        SecurityAdvisoryEvent                    Event = "security_advisory"
67
        StatusEvent                              Event = "status"
68
        TeamEvent                                Event = "team"
69
        TeamAddEvent                             Event = "team_add"
70
        WatchEvent                               Event = "watch"
71
)
72

73
// EventSubtype defines a GitHub Hook Event subtype
74
type EventSubtype string
75

76
// GitHub hook event subtypes
77
const (
78
        NoSubtype     EventSubtype = ""
79
        BranchSubtype EventSubtype = "branch"
80
        TagSubtype    EventSubtype = "tag"
81
        PullSubtype   EventSubtype = "pull"
82
        IssueSubtype  EventSubtype = "issues"
83
)
84

85
// Option is a configuration option for the webhook
86
type Option func(*Webhook) error
87

88
// Options is a namespace var for configuration options
89
var Options = WebhookOptions{}
90

91
// WebhookOptions is a namespace for configuration option methods
92
type WebhookOptions struct{}
93

94
// Secret registers the GitHub secret
95
func (WebhookOptions) Secret(secret string) Option {
96
        return func(hook *Webhook) error {
97
                hook.secret = secret
98
                return nil
99
        }
100
}
101

102
// Webhook instance contains all methods needed to process events
1✔
103
type Webhook struct {
2✔
104
        secret string
1✔
105
}
1✔
106

1✔
107
// New creates and returns a WebHook instance denoted by the Provider type
108
func New(options ...Option) (*Webhook, error) {
109
        hook := new(Webhook)
110
        for _, opt := range options {
111
                if err := opt(hook); err != nil {
112
                        return nil, errors.New("Error applying Option")
113
                }
114
        }
115
        return hook, nil
1✔
116
}
1✔
117

2✔
118
// Parse verifies and parses the events specified and returns the payload object or an error
1✔
119
func (hook Webhook) Parse(r *http.Request, events ...Event) (interface{}, error) {
×
120
        defer func() {
×
121
                _, _ = io.Copy(ioutil.Discard, r.Body)
122
                _ = r.Body.Close()
1✔
123
        }()
124

125
        if len(events) == 0 {
126
                return nil, ErrEventNotSpecifiedToParse
53✔
127
        }
106✔
128
        if r.Method != http.MethodPost {
53✔
129
                return nil, ErrInvalidHTTPMethod
53✔
130
        }
53✔
131

132
        event := r.Header.Get("X-GitHub-Event")
53✔
133
        if event == "" {
×
134
                return nil, ErrMissingGithubEventHeader
×
135
        }
53✔
136
        gitHubEvent := Event(event)
×
137

×
138
        var found bool
139
        for _, evt := range events {
53✔
140
                if evt == gitHubEvent {
54✔
141
                        found = true
1✔
142
                        break
1✔
143
                }
52✔
144
        }
52✔
145
        // event not defined to be parsed
52✔
146
        if !found {
104✔
147
                return nil, ErrEventNotFound
103✔
148
        }
51✔
149

51✔
150
        payload, err := ioutil.ReadAll(r.Body)
151
        if err != nil || len(payload) == 0 {
152
                return nil, ErrParsingPayload
153
        }
53✔
154

1✔
155
        // If we have a Secret set, we should check the MAC
1✔
156
        if len(hook.secret) > 0 {
157
                signature := r.Header.Get("X-Hub-Signature")
51✔
158
                if len(signature) == 0 {
52✔
159
                        return nil, ErrMissingHubSignatureHeader
1✔
160
                }
1✔
161
                mac := hmac.New(sha1.New, []byte(hook.secret))
162
                _, _ = mac.Write(payload)
163
                expectedMAC := hex.EncodeToString(mac.Sum(nil))
100✔
164

50✔
165
                if !hmac.Equal([]byte(signature[5:]), []byte(expectedMAC)) {
51✔
166
                        return nil, ErrHMACVerificationFailed
1✔
167
                }
1✔
168
        }
169

49✔
170
        switch gitHubEvent {
49✔
171
        case CheckRunEvent:
49✔
172
                var pl CheckRunPayload
49✔
173
                err = json.Unmarshal([]byte(payload), &pl)
49✔
174
                return pl, err
49✔
175
        case CheckSuiteEvent:
50✔
176
                var pl CheckSuitePayload
1✔
177
                err = json.Unmarshal([]byte(payload), &pl)
1✔
178
                return pl, err
179
        case CommitCommentEvent:
180
                var pl CommitCommentPayload
48✔
181
                err = json.Unmarshal([]byte(payload), &pl)
1✔
182
                return pl, err
1✔
183
        case CreateEvent:
1✔
184
                var pl CreatePayload
1✔
185
                err = json.Unmarshal([]byte(payload), &pl)
1✔
186
                return pl, err
1✔
187
        case DeleteEvent:
1✔
188
                var pl DeletePayload
1✔
189
                err = json.Unmarshal([]byte(payload), &pl)
1✔
190
                return pl, err
1✔
191
        case DeploymentEvent:
1✔
192
                var pl DeploymentPayload
1✔
193
                err = json.Unmarshal([]byte(payload), &pl)
1✔
194
                return pl, err
1✔
195
        case DeploymentStatusEvent:
1✔
196
                var pl DeploymentStatusPayload
1✔
197
                err = json.Unmarshal([]byte(payload), &pl)
1✔
198
                return pl, err
1✔
199
        case ForkEvent:
1✔
200
                var pl ForkPayload
1✔
201
                err = json.Unmarshal([]byte(payload), &pl)
1✔
202
                return pl, err
1✔
203
        case GollumEvent:
1✔
204
                var pl GollumPayload
1✔
205
                err = json.Unmarshal([]byte(payload), &pl)
1✔
206
                return pl, err
1✔
207
        case InstallationEvent, IntegrationInstallationEvent:
1✔
208
                var pl InstallationPayload
1✔
209
                err = json.Unmarshal([]byte(payload), &pl)
1✔
210
                return pl, err
1✔
211
        case InstallationRepositoriesEvent, IntegrationInstallationRepositoriesEvent:
1✔
212
                var pl InstallationRepositoriesPayload
1✔
213
                err = json.Unmarshal([]byte(payload), &pl)
1✔
214
                return pl, err
1✔
215
        case IssueCommentEvent:
1✔
216
                var pl IssueCommentPayload
1✔
217
                err = json.Unmarshal([]byte(payload), &pl)
1✔
218
                return pl, err
1✔
219
        case IssuesEvent:
1✔
220
                var pl IssuesPayload
1✔
221
                err = json.Unmarshal([]byte(payload), &pl)
1✔
222
                return pl, err
1✔
223
        case LabelEvent:
1✔
224
                var pl LabelPayload
1✔
225
                err = json.Unmarshal([]byte(payload), &pl)
2✔
226
                return pl, err
2✔
227
        case MemberEvent:
2✔
228
                var pl MemberPayload
2✔
229
                err = json.Unmarshal([]byte(payload), &pl)
2✔
230
                return pl, err
2✔
231
        case MembershipEvent:
2✔
232
                var pl MembershipPayload
2✔
233
                err = json.Unmarshal([]byte(payload), &pl)
2✔
234
                return pl, err
2✔
235
        case MetaEvent:
2✔
236
                var pl MetaPayload
2✔
237
                err = json.Unmarshal([]byte(payload), &pl)
1✔
238
                return pl, err
1✔
239
        case MilestoneEvent:
1✔
240
                var pl MilestonePayload
1✔
241
                err = json.Unmarshal([]byte(payload), &pl)
1✔
242
                return pl, err
1✔
243
        case OrganizationEvent:
1✔
244
                var pl OrganizationPayload
1✔
245
                err = json.Unmarshal([]byte(payload), &pl)
1✔
246
                return pl, err
1✔
247
        case OrgBlockEvent:
1✔
248
                var pl OrgBlockPayload
1✔
249
                err = json.Unmarshal([]byte(payload), &pl)
1✔
250
                return pl, err
1✔
251
        case PageBuildEvent:
1✔
252
                var pl PageBuildPayload
1✔
253
                err = json.Unmarshal([]byte(payload), &pl)
×
254
                return pl, err
×
255
        case PingEvent:
×
256
                var pl PingPayload
×
257
                err = json.Unmarshal([]byte(payload), &pl)
1✔
258
                return pl, err
1✔
259
        case ProjectCardEvent:
1✔
260
                var pl ProjectCardPayload
1✔
261
                err = json.Unmarshal([]byte(payload), &pl)
1✔
262
                return pl, err
1✔
263
        case ProjectColumnEvent:
1✔
264
                var pl ProjectColumnPayload
1✔
265
                err = json.Unmarshal([]byte(payload), &pl)
1✔
266
                return pl, err
1✔
267
        case ProjectEvent:
1✔
268
                var pl ProjectPayload
1✔
269
                err = json.Unmarshal([]byte(payload), &pl)
1✔
270
                return pl, err
1✔
271
        case PublicEvent:
1✔
272
                var pl PublicPayload
1✔
273
                err = json.Unmarshal([]byte(payload), &pl)
1✔
274
                return pl, err
1✔
275
        case PullRequestEvent:
1✔
276
                var pl PullRequestPayload
1✔
277
                err = json.Unmarshal([]byte(payload), &pl)
1✔
278
                return pl, err
1✔
279
        case PullRequestReviewEvent:
1✔
280
                var pl PullRequestReviewPayload
1✔
281
                err = json.Unmarshal([]byte(payload), &pl)
1✔
282
                return pl, err
1✔
283
        case PullRequestReviewCommentEvent:
1✔
284
                var pl PullRequestReviewCommentPayload
1✔
285
                err = json.Unmarshal([]byte(payload), &pl)
1✔
286
                return pl, err
1✔
287
        case PushEvent:
1✔
288
                var pl PushPayload
1✔
289
                err = json.Unmarshal([]byte(payload), &pl)
1✔
290
                return pl, err
1✔
291
        case ReleaseEvent:
1✔
292
                var pl ReleasePayload
1✔
293
                err = json.Unmarshal([]byte(payload), &pl)
1✔
294
                return pl, err
1✔
295
        case RepositoryEvent:
1✔
296
                var pl RepositoryPayload
1✔
297
                err = json.Unmarshal([]byte(payload), &pl)
1✔
298
                return pl, err
1✔
299
        case RepositoryVulnerabilityAlertEvent:
1✔
300
                var pl RepositoryVulnerabilityAlertPayload
1✔
301
                err = json.Unmarshal([]byte(payload), &pl)
1✔
302
                return pl, err
1✔
303
        case SecurityAdvisoryEvent:
1✔
304
                var pl SecurityAdvisoryPayload
1✔
305
                err = json.Unmarshal([]byte(payload), &pl)
1✔
306
                return pl, err
1✔
307
        case StatusEvent:
1✔
308
                var pl StatusPayload
1✔
309
                err = json.Unmarshal([]byte(payload), &pl)
1✔
310
                return pl, err
1✔
311
        case TeamEvent:
1✔
312
                var pl TeamPayload
1✔
313
                err = json.Unmarshal([]byte(payload), &pl)
2✔
314
                return pl, err
2✔
315
        case TeamAddEvent:
2✔
316
                var pl TeamAddPayload
2✔
317
                err = json.Unmarshal([]byte(payload), &pl)
1✔
318
                return pl, err
1✔
319
        case WatchEvent:
1✔
320
                var pl WatchPayload
1✔
321
                err = json.Unmarshal([]byte(payload), &pl)
1✔
322
                return pl, err
1✔
323
        default:
1✔
324
                return nil, fmt.Errorf("unknown event %s", gitHubEvent)
1✔
325
        }
1✔
326
}
1✔
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