Good programmers are lazy. It’s a common euphemism in the software development world: a humorous, counterintuitive statement that describes a real phenomenon. Good programmers look for simple, efficient solutions to hard problems. Often, that means making our machines do the work for us in new ways. Today, we will be exploring how to make your computer automatically check code for cybersecurity risks on every commit to a Git repository so that us devs will not need to remember to do that on our own.
1. Git Hooks
Git is a modern and popular code repository. Through its Git Hooks feature, you can extend its built-in capabilities with custom scripts that are run when certain repository events occur, such as commits.
Examples of common custom scripts that a developer might want to run when a commit action occurs are running tests, code formatting or even commit message reformatting to include the ticket number. The beauty of this pre-commit hook is that the developer doesn’t have to remember (and potentially forget) to run these commands on their code prior to each time they commit a change.
If a project is set up to use a Git repository, it will have a “.git” folder at the top level of the project’s directory structure. Within that folder is a “hooks” folder, which contains sample scripts for the different repository events, such as “pre-commit.sample.” It may also contain script files for any hooks that you’ve previously created.
We’re interested in making a pre-commit hook to scan our code for cybersecurity vulnerabilities every time we commit changes. To create a new git hook script file, simply copy the “pre-commit.sample” file, rename it to remove the “.sample” file extension, open the file in a text editor and delete the sample script contents.
Pro tip: Alternatively, we could make a new file named “pre-commit,” but on Unix-like machines, we’ll need to give it permission to be executed. An easy way to do that is by running the following command:
chmod +x .git/hooks/pre-commit
2. CodeSec pre-commit shell script
Git runs the pre-commit script before actually creating the commit for our code changes. As such, the requirements for our script to find cybersecurity vulnerabilities are:
- Run both contrast scan and contrast audit commands to scan for vulnerabilities in the project code and in any third-party libraries;
- Examine the output of each of those commands to see if any critical or high-risk vulnerabilities are found; and
- Stop the commit process if risks are found, but continue with the commit if none are found.
To accomplish the first requirement, we need to have CodeSec by Contrast installed on our local development machine. Installation instructions are available on Contrast Security’s Developer Central hub. We also illustrated, step-by-step, how easy it is to install CodeSec in a previous article about finding Log4j vulnerabilities.
Once CodeSec is installed, we can pipe the output of the CodeSec commands to the Grep tool to search for the keywords “CRITICAL” and “HIGH,” which will be present if CodeSec lists out any critical or high-risk vulnerabilities. Finally, if Grep finds a vulnerability in the output, we can exit the commit process early without actually committing any of your code changes.
This is an example output for contrast audit when a high-risk vulnerability is found.
We can see in the screenshot that CodeSec found a high-risk vulnerability, indicated by the “HIGH” keyword.
Below is the full code of the pre-commit script where Grep searches the CodeSec output for the “CRITICAL” and “HIGH” keywords and exits the commit process early if found:
#!/bin/sh
#Existing pre-commit scripts could go here....
if contrast scan | grep -e CRITICAL -e HIGH; then
echo "\n💩 One or more vulnerabilities found in code. Please run 'contrast scan' for more details."
exit 1
fi
if contrast audit | grep -e CRITICAL -e HIGH; then
echo "\n💩 One or more vulnerabilities found in libraries. Please run 'contrast audit' for more details."
exit 1
fi
The script functions just as described above. It’s a shell script with two “if” blocks. The conditional expressions of each “if” calls the CodeSec commands, pipes the output to Grep so that it can search for critical or high-risk vulnerability listings, and exits early from the commit process if any are found. To use this script, just add it to the pre-commit file in the .git/hooks directory that we made in the first part of this article.
This is what it looks like in action for a Git commit:
Conclusion
The key feature in this example is that CodeSec can find cybersecurity vulnerabilities in our code, and Grep can search the output of CodeSec. Together, these two tools are a springboard for software process automation. In our example, it prevents risky code from being committed to the project repository every time a developer tries to commit code. This is like having an in-house cybersecurity expert code review every change without forgetting to check something or making a mistake, and doing it every day, for free. This is what it means to be a lazy programmer who works smart instead of hard: A good programmer makes the machine do the work instead.