visit
()
As the animation above shows, automated tests will run in when pull requests are created. Heroku CI is a cloud continuous integration tool from Heroku; it can either automatically detect the language and run default commands (e.g. npm test) or can be configured via the app.json file. CI results are available in both the pull request details in GitHub and the Heroku interface.
For a successful CI build, create a new review of the application and deploy it to a new temporary Heroku environment using . The new environment link is available in GitHub pull request view, allowing engineers to easily check CI results or run any manual tests immediately.
After merging the pull request, the new review of the application is available in pre-production environments using . Then, the review can be promoted to production.
Note that while some pieces of Heroku flow are included with a free account (namely pipelines and review apps) some features do incur a fee (Heroku CI).Safely Upgrade Dependencies with Security Vulnerabilities
You probably already know that you should upgrade dependencies with known vulnerabilities. It can be pretty time-consuming to identify and update those dependencies. Thankfully, you can automate the majority of this work. GitHub provides a dependency vulnerability scanner, also known as , which can be enabled in GitHub’s Security settings. By default, it will add warnings to the GitHub interface when identifying a dependency with a known vulnerability.While it’s a useful feature, it still requires you to check the warnings and manually create pull requests to upgrade the affected dependencies and create a fixed version. Fortunately, there's a beta feature in Dependabot that automatically creates pull requests to fix known vulnerabilities.To enable this feature, simply add a .github/dependabot.yml file to your repository:
# Basic dependabot.yml file for JavaScript application
# check docs for other dependencies
version: 2
updates:
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "daily"
Pull request created by Dependabot to address a known vulnerability
While the pull request will upgrade the affected library version, it's still important to verify that the application will work as expected after the upgrade. The pull request raised by Dependabot will run CI tests and will be deployed to a new Heroku environment. Both versions are accessible from the GitHub interface.Checks from Pull Request view in GitHub
After merging the pull request, the pipeline will run CI tests and deploy it to pre-production environments. Then, it can be promoted to production.Heroku Pipeline view
Setting up Dependabot and Heroku Flow will automate most of the manual work required to address security vulnerabilities in libraries and dependencies.Identify Security Bugs Early
Naturally, the ideal time to catch security bugs is before deploying to production. Many different tools can run static code analysis and identify problematic code before merging the code to the main branch. As an example, let’s consider a simple Node.js application. Developers commonly use to enforce consistent coding styles and to catch common problems. Enabling will also identify common security bugs:.eslintrc
...
"plugins": [
"security"
],
"extends": [
"plugin:security/recommended"
]
...
app.json
{
"environments": {
"test": {
"scripts": {
"test": "bash ./ci.sh"
}
}
}
}
ci.sh
#!/bin/bash
set -eux
#### Running unit tests
npm test
#### Searching for security problems
npm run lint
Prevent Unauthorized Components or Libraries
Some organizations heavily emphasize controlling application deployment complexity and implementing centralized controls for all applications. For example, these controls may prevent the use of Redis add-on or a specific JavaScript library. All Heroku components for an application are defined in the file as code. This opens up the possibility for pre-deployment checks. Infrastructure engineers can create a centralized script to prevent specific components from being deployed, and ensure all applications pass the same checks.For example, let's consider the centralized script infrastructure-checks.sh shown below. It’s currently available in a public git repository "mygithubaccount/infrastructure-scripts". For this tutorial, let's say your goal is to prevent all Heroku add-ons from deploying.
infrastructure-scripts.sh
#!/bin/bash
set -eux
ADDONS=$(cat app.json | jq '.addons')
# Prevents all addons
if [[ "$ADDONS" != "null" ]]; then
echo "Add-ons are not allowed"
exit 1
fi
app.json
{
"environments": {
"test": {
"scripts": {
"test": "bash ./ci.sh"
}
}
}
}
ci.sh
#!/bin/bash
set -eux
INFRA_SCRIPTS_REPOSITORY="mygithubaccount/infrastructure-scripts"
wget //raw.githubusercontent.com/${INFRA_SCRIPTS_REPOSITORY}/master/infrastructure-checks.sh
bash ./infrastructure-checks.sh
# Add as well all commands to run all other tests
...