LGTM Devlog 10: Capturing the GitHub webhook for fork requests
Tags: devjournal, python, serverless, cloud
Published: 2020-12-31 10:15:38

Now that we have our boilerplates set up, it's time to look at what data GitHub gives us via webhook when we make a fork request.

I'm going to set up webhooks for the repo, and tell it to only send me webhooks for Forks.

![Webhook settings](https://dev-to-uploads.s3.amazonaws.com/i/29fdkla7yq7javii6517.png)
 
Some of the settings I used:
* **Payload URL** This will eventually be our cloud functions endpoint. I am using the hugely useful [ngrok](https://ngrok.com/) service for temporarily tunneling an HTTS-equipped endpoint to my local machine without having to deal with DNS, and portforwarding.
* **Content type** I want to use json data, so this is set to `application/json`
* **Secret** the webhook will use this secret to calculate a signature and add that to the request header, as an added layer of security, so that we can reject imposters trying to trigger our endpoint with fake data.
* **SSL verification** This causes GitHub to check that our endpoint has a valid SSL certificate when sending data. Having this on is the norm these days, it's unusual to not have it. Because we're using Firebase Functions, SSL will be set up for us already so we don't have to worry about it
* **Which events?** We only need to hear about Forks at this point, so I select that

With that set up, save it, and then go create another GitHub account from which I can try to fork this repo (I called the account "LGTM-garry" because I'll be using this account for one of the NPCs later). Once I do that, I can run ngrok, paste the new temporary URL into the github webhooks section, and receive the webhook data. Since I don't actually have an endpoint set up for ngrok to forward onto, it generates a 502 Bad Gateway error, but I can still access the payload via ngrok's local web interface.

![ngrok payload](https://dev-to-uploads.s3.amazonaws.com/i/6lzyelnjz2z0vrw9iicf.png)

The same payload is available under "Recent Deliveries" section of Github:

![Recent deliveries](https://dev-to-uploads.s3.amazonaws.com/i/dndwm3fq0vj6dz5b8vbh.png)
 
The whole payload is quite big, and appears to be full of URLs that might be useful. I'm guessing GitHub's policy on this is to generate all the URLs themselves to make it easy for the consumer of the API to use, to avoid the consumer having to use any logic on their end to construct the URLs. This means GitHub are free to change the url format, without breaking consumer code.

After looking through the JSON payload, this appears to be the only relevant parts that we need:
```json
{
  "forkee": {
    "owner": {
      "login": "LGTM-garry",
      "id": 76662434,
    },
    "url": "https://api.github.com/repos/LGTM-garry/lgtm"
  },
  "repository": {
    "full_name": "meseta/lgtm"
  }
}
```
This payload contains:
* The GitHub username and ID of the account that did the forking. We need this to associate game data with an account, and I think we need to store the ID as well to avoid things breaking if they change their username.
* The API URL of the resulting fork. We need this so that we can send issues to it later. I _think_ it's this URL we need, though I may well find out it's a different URL later, we'll see.
* The repository that was forked. We need this to double check this is the repo that was forked. If in the future for some reason we have multiple repos, I don't want to get confused about which one was just forked.

While the header contains these headers for validation:
* X-Hub-Signature: the SHA1 signature
* X-Hub-Signature-256: The SHA256 signature

GitHub's [documentation](https://docs.github.com/en/free-pro-team@latest/developers/webhooks-and-events/securing-your-webhooks) about these signatures describes to us how to implement signature checking, and a quick google search shows up some [Python/Flask examples](https://github.com/onfido/api-python-client/issues/2#issuecomment-668354100) that we can crib.