The story so far
We’ve explored pre-receive hooks as implemented in GitHub Enterprise, and specifically how and when to implement them. That said, pre-receive hooks are not a panacea, and there are other tools that are better suited when you want to add constraints when pushing your code.
One of the first use cases that comes to mind is security scanning. Catching private keys, security credentials, and other access codes before they are even made public and refusing pushes sounds like a perfect use for pre-receive hooks! However the constraints inherent to pre-receive hooks make them a poor choice for this:
- Server-side Git data does not have a concept of working copy, which means that anything that needs to access the contents of a modified file has to checkout that file first.
- Pre-receive hooks run after data has been recorded in the Git history, but before it has been copied back to the origin. This means that the commit history must be rewritten to remove the whole file or revision, which comes with its own challenges. In comparison, commits metadata can be modified with
git commit --amend, for instance.
- Larger pushes, which can contain either a large number of files, a large number of commits, or large files (or both!) add to the pre-receive hook runtime and will hit the preset timeout. Bypassing said timeout is not possible, and would severely impact the stability and performance of your instance otherwise.
Two options are available:
Use pre-commit hooks instead. This ensures critical data never leaves the workstation in the first place. Changes cannot be saved until the issues are addressed, and execution time is not constrained by timeouts.
Use webhooks and an external service to scan for known critical data. This has several key benefits. When critical data is detected, the external service is configured to automatically roll the credentials and notify the relevant stakeholders.
- You can make the distinction between test data and actual live data by comparing them against your infrastructure, instead of rejecting based on a pattern.
- Having a system that can automatically invalidate and renew keys, tokens, and other critical data prepares you to handle security incidents that happen outside of GitHub Enterprise. For instance, dealing with compromised workstations or storage devices.
- You can run as many checks on as many patterns as you want, without exceeding time limits.
Let’s say you want commits to match a specific coding style, or confirm the work done is tracked against the correct issue in your issue tracker. Again, using pre-receive hooks delivers immediate feedback…or does it?
Similarly to security scanning, pre-receive hooks do not handle large amounts of data very well. They also make it difficult to get an accurate report of the style violations. Additionally, relying on external systems to block or allow pushes can have strict consequences when a third-party server is unavailable or experiencing degraded performance.
A better alternative would be to configure protected branches and required status checks:
- Configure a webhook to trigger on every push that will forward the push payload to a build server of your choice.
- Then configure your required checks, and use the Statuses API endpoint to set the status, being one of
- Finally, configure your protected branches to prevent changes being committed directly to your default branch, and enforce required status checks using the status you’ve implemented.
There are several advantages to this process:
- Work is not blocked, but changes cannot be merged until issues are fixed. Further commits to fix issues can be pushed, instead of having to rewrite history.
- You’re not depending on a third-party system being online and responding quickly 100% of the time.
- A select group of users can fast track urgent changes by dismissing required checks, for instance to implement an emergency security fix.
- You can identify build errors ahead of time, and once your changes are confirmed to be working, you can over and fix the syntax as well.
While pre-receive hooks are a powerful Git feature available to GitHub Enterprise administrators, they act as a complement to other features that assist your workflow rather than impede it. These are just a couple scenarios where pre-receive hooks are not the best solution. Have you run into other situations that seemed like they would be perfect for using pre-receive hooks but then caused issues? Let us know in the comments below!