01 Apr 2021
Run OWASP DependencyCheck as a GitHub action on a gradle project
Say, you are a very security-oriented developer, who doesn’t want to allow any publicly disclosed vulnerabilities in their project dependency tree. To that end, you have OWASP’s DependencyCheck configured on your gradle project as a plugin. For example, such a configuration could look like the following:
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'org.owasp:dependency-check-gradle:6.1.5'
}
}
apply plugin: 'org.owasp.dependencycheck'
dependencyCheck {
failBuildOnCVSS = 2
cveValidForHours=24
}
This way, every time you run the command ./gradlew check
(or ./gradlew dependencyCheckAnalyze
for that matter), the build pipeline automatically checks NIST’s CVEs database for any vulnerabilities against the dependencies of your project, and fails the local build if a CVE is found with a CVSS score higher than or equal to 2.
It turns out, however, that not everyone on your development team is as diligent as you are. Yes, you could add a git hook to your repository to force the check
task to execute on each PR. But that can easily be skipped by passing --no-verify
to the git push
command.
GitHub Action
If your project is hosted on GitHub, a very simple solution is to just run the check task as a GitHub Action. Just drop a .yml
file under .github/workflows/
, with the following content:
name: DependencyCheck with Gradle
on: pull_request
jobs:
depCheck:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up JDK 1.8
uses: actions/setup-java@v1
with:
java-version: 1.8
- uses: eskatos/gradle-command-action@v1
with:
arguments: dependencyCheckAnalyze
And that’s it! This simple workflow will execute on each PR, and report the result as a notification in GitHub, assuming you have configured it to do so in your settings.
Optimizing the workflow
As part of its operation, the plugin will automatically download a copy of the NIST NVD database, and cache it locally. While this is ideal for local runs, it doesn’t work for a CI setup. Basically, we need to introduce a way to cache the database, which normally lives under ~/.gradle/dependency-check-data
. The solution is to add the following step before running the gradle command action:
- name: Cache Dependency Check DB
uses: actions/cache@v2
with:
path: ~/.gradle/dependency-check-data
key: $-gradle-$
restore-keys: $-gradle
Publishing the result
The one remaining thing is to make sure the results of the dependency check are published, no matter the result. This is done using a simple upload artifact action, after the check task completes:
- name: Backup Report
if: "$"
uses: actions/upload-artifact@v2
with:
name: dependency-check-report.html
path: ./build/reports/dependency-check-report.html
Putting it altogether
And there you go: a dependency check on any PR, running alongside your repo.
PS: I know I am not supposed to tell you what to do, but, you know, you could always follow me on Twitter