Fixing the Internet one NPM package at a time

How to patch a bug, use the fix in prod and submit the pull request in five minutes.

Problem

Today I tried to write a GitHub Integration. The integration application receives commit messages from a registered repo and does some cool stuff. The messages are delivered via a webhook, registered with GitHub. To avoid parsing the messages myself, I found the package express-github-webhook by searching npms.io. The code for my server is very simple

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// requires skipped for brevity
const webhookHandler = githubWebHook({
path: '/',
secret: 'secret'
})
let app = express();
app.use(bodyParser.json());
app.use(webhookHandler);
webhookHandler.on('*', function (event, repo, data) {
console.log('event', event)
console.log('data', data)
});
webhookHandler.on('event', function (repo, data) {
});
webhookHandler.on('reponame', function (event, data) {
console.log('reponame', event, 'data', data)
});
webhookHandler.on('error', function (err, req, res) {
console.log('error', err)
});
const port = process.env.PORT || 6001
app.listen(port)
console.log('listening on port %d', port)

Great! To test how this is working out, I have started the server at localhost:6001 and tunneled the messages from external temp address using ngrok service. For example the external website is relaying all messages https://a1c5dd12.ngrok.io -> localhost:6001.

Yet the server displayed an error as soon as I clicked "register", because GitHub tries to deliver a test message.

1
2
3
listening on port 6001
TypeError: Cannot read property 'name' of undefined
at githookHandler (/node_modules/express-github-webhook/index.js:80:38)

Hmm, what is happening?

Investigation

Opening the offending 3rd party module file at that line shows the following code

1
2
3
// parse payload
let payloadData = req.body; // line 79
const repo = payloadData.repository.name; // line 80

Ok, but what is the payload in the GitHub test message? Let us print the payloadData before using it. I changed the code in /node_modules/express-github-webhook/index.js to print the object before trying to access payloadData.repository. Then I triggered the test message POST again from GitHub UI.

1
2
3
4
let payloadData = req.body;
console.log(payloadData)
console.log('event', event)
const repo = payloadData.repository.name;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
listening on port 6001
{
zen: 'Half measures are as bad as nothing at all.',
hook_id: 27550684,
hook:
{ type: 'Integration',
id: 12859684,
name: 'web',
active: true,
events: [ 'push' ],
config:
{ content_type: 'json',
insecure_ssl: '0',
secret: '********',
url: 'https://a1c5dd12.ngrok.io'
},
updated_at: '2017-03-26T22:30:28Z',
created_at: '2017-03-26T22:30:28Z',
integration_id: 1878
}
}
event ping

There is no repository field in the payload for the "ping" event! Let us fix the crashing code.

1
2
3
4
5
6
7
let payloadData = req.body;
const repo = payloadData.repository && payloadData.repository.name;
githookHandler.emit('*', event, repo, payloadData);
githookHandler.emit(event, repo, payloadData);
if (repo) {
githookHandler.emit(repo, event, payloadData);
}

Trying delivering the event again - and GitHub is reporting success!

Fixing the problem

What do we do now? We need to deploy the integration server, so somehow we need to use the patched version right now. Luckily this is extremely easy with GitHub and NPM.

  1. Fork the original GitHub repo Gisonrg/express-github-webhook to my own bahmutov/express-github-webhook.
  2. Fix the code in the fork. The change is so small, we can even use the online editor. I describe my commits using semantic convention.

    1
    git commit -m "fix(parsing): do not assume there is a repository"

    This code got the commit SHA e84170...

  3. Point the express-github-webhook NPM dependency at my GitHub repository. We can even leave the previous NPM registry version there, since the second key value overwrites the previous ones (it is how I write comments in my JSON files)

    1
    2
    3
    4
    5
    6
    {
    "dependencies": {
    "express-github-webhook": "^1.0.5",
    "express-github-webhook": "bahmutov/express-github-webhook"
    }

    }

  4. Run the install and notice that we get our patch now.

    1
    2
    3
    $ npm i
    code-filters-github-webhook@1.0.0
    └── express-github-webhook@1.0.4 (git://github.com/bahmutov/express-github-webhook.git#e84170fb7b1298fe033aa860595ee19ef6479a2e)

    If we really wanted you could even specify particular commit SHA, like "express-github-webhook": "bahmutov/express-github-webhook#e84170" to be more precise and avoid accidentally using latest.

  5. Test the GitHub "ping" event again - still works!
  6. Be a good Open Source Citizen and create a Pull Request from our patched repository back to the original one, you can see my pull request here Gisonrg/express-github-webhook/pull/2

And that's how Open Source and NPM make it simple to find, use and fix all the code around us.