Skip to content

Commit 36eefdf

Browse files
committed
Fix event parsing for ping
Although GitHub docs say 'action' is a common field, it's not _required_ for the ping event. We need to parse the event action from the request headers instead.
1 parent 7dbf8a1 commit 36eefdf

File tree

2 files changed

+32
-25
lines changed

2 files changed

+32
-25
lines changed

test_webhook.py

Lines changed: 24 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -105,35 +105,35 @@ async def test_github_webhook_errors(aiohttp_client, monkeypatch):
105105
monkeypatch.setattr(webhook, 'verify_signature',
106106
mock.Mock(verify_signature, return_value=True))
107107

108+
valid_headers = {
109+
'X-GitHub-Delivery': 'foo',
110+
'X-Hub-Signature-256': 'unused',
111+
'X-GitHub-Event': 'ping',
112+
}
113+
108114
# Data should be JSON.
109-
resp = await client.post(
110-
'/gh/non-existent-repo',
111-
headers={'X-GitHub-Delivery': 'foo', 'X-Hub-Signature-256': 'unused'},
112-
data='}{')
115+
resp = await client.post('/gh/non-existent-repo', headers=valid_headers,
116+
data='}{')
113117
assert resp.status == 400
114118
assert 'Invalid data input' in await resp.text()
115119

116120
# Some data fields are required.
117-
resp = await client.post(
118-
'/gh/non-existent-repo',
119-
headers={'X-GitHub-Delivery': 'foo', 'X-Hub-Signature-256': 'unused'},
120-
data='{}')
121+
resp = await client.post('/gh/non-existent-repo', headers=valid_headers,
122+
data='{}')
121123
assert resp.status == 400
122124
assert 'Missing required fields' in await resp.text()
123125

124126
resp = await client.post(
125-
'/gh/non-existent-repo',
126-
headers={'X-GitHub-Delivery': 'foo', 'X-Hub-Signature-256': 'unused'},
127-
data='{"action": "ping", "sender": "QuLogic", "organization": "foo",'
127+
'/gh/non-existent-repo', headers=valid_headers,
128+
data='{"sender": "QuLogic", "organization": "foo",'
128129
' "repository": "foo"}')
129130
assert resp.status == 400
130131
assert 'incorrect organization' in await resp.text()
131132

132133
resp = await client.post(
133-
'/gh/non-existent-repo',
134-
headers={'X-GitHub-Delivery': 'foo', 'X-Hub-Signature-256': 'unused'},
135-
data='{"action": "ping", "sender": "QuLogic", '
136-
'"organization": "matplotlib", "repository": "foo"}')
134+
'/gh/non-existent-repo', headers=valid_headers,
135+
data='{"sender": "QuLogic", "organization": "matplotlib",'
136+
' "repository": "foo"}')
137137
assert resp.status == 400
138138
assert 'incorrect repository' in await resp.text()
139139

@@ -149,11 +149,16 @@ async def test_github_webhook_valid(aiohttp_client, monkeypatch):
149149
ur_mock = mock.Mock(update_repo, return_value=None)
150150
monkeypatch.setattr(webhook, 'update_repo', ur_mock)
151151

152+
valid_headers = {
153+
'X-GitHub-Delivery': 'foo',
154+
'X-Hub-Signature-256': 'unused',
155+
}
156+
152157
# Ping event just returns success.
153158
resp = await client.post(
154159
'/gh/non-existent-repo',
155-
headers={'X-GitHub-Delivery': 'foo', 'X-Hub-Signature-256': 'unused'},
156-
data='{"action": "ping", "sender": "QuLogic", "hook_id": "foo",'
160+
headers={**valid_headers, 'X-GitHub-Event': 'ping'},
161+
data='{"sender": "QuLogic", "hook_id": 1234,'
157162
' "zen": "Beautiful is better than ugly.",'
158163
' "organization": "matplotlib",'
159164
' "repository": "non-existent-repo"}')
@@ -163,9 +168,8 @@ async def test_github_webhook_valid(aiohttp_client, monkeypatch):
163168
# Push event should run an update.
164169
resp = await client.post(
165170
'/gh/non-existent-repo',
166-
headers={'X-GitHub-Delivery': 'foo', 'X-Hub-Signature-256': 'unused'},
167-
data='{"action": "push", "sender": "QuLogic",'
168-
' "organization": "matplotlib",'
171+
headers={**valid_headers, 'X-GitHub-Event': 'push'},
172+
data='{"sender": "QuLogic", "organization": "matplotlib",'
169173
' "repository": "non-existent-repo"}')
170174
assert resp.status == 200
171175
ur_mock.assert_called_once_with(

webhook.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,10 @@ async def github_webhook(request: web.Request):
8383
signature = request.headers['X-Hub-Signature-256']
8484
except KeyError:
8585
raise web.HTTPBadRequest(reason='No signature given')
86+
try:
87+
event = request.headers['X-GitHub-Event']
88+
except KeyError:
89+
raise web.HTTPBadRequest(reason='No event given')
8690
repo = request.match_info.get('repo')
8791
log.info('%s: Received webhook for %s', delivery, repo)
8892

@@ -96,26 +100,25 @@ async def github_webhook(request: web.Request):
96100

97101
# https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads#webhook-payload-object-common-properties
98102
try:
99-
action = data['action']
100103
sender = data['sender']
101104
organization = data['organization']
102105
repository = data['repository']
103106
except KeyError:
104107
raise web.HTTPBadRequest(reason='Missing required fields')
105108
log.info('%s: Received %s event from %s on %s/%s',
106-
delivery, action, sender, organization, repository)
109+
delivery, event, sender, organization, repository)
107110

108111
if organization != 'matplotlib':
109112
raise web.HTTPBadRequest(reason=f'{delivery}: incorrect organization')
110113
if repository != repo:
111114
raise web.HTTPBadRequest(reason=f'{delivery}: incorrect repository')
112115

113-
if action == 'ping':
116+
if event == 'ping':
114117
log.info('%s: Ping %s: %s', delivery, data['hook_id'], data['zen'])
115118
return web.Response(status=200)
116119

117-
if action != 'push':
118-
log.info('%s: Ignoring webhook for unused action %s', delivery, action)
120+
if event != 'push':
121+
log.info('%s: Ignoring webhook for unused event %s', delivery, event)
119122
return web.Response(status=200)
120123

121124
checkout = Path(os.environ.get('SITE_DIR', 'sites'), repository)

0 commit comments

Comments
 (0)