How to run CodeQL scans on Jenkins
Question
My repository requires scans be run on Jenkins. How can I configure Jenkins to run the scans?
This is Step #5 for configuring CodeQL scans for Jenkins CI. This step is performed after the
remove codeql-analysis workflow
and is the final step in configuring CodeQL scans for Jenkins CI.
Answer
If you require scans to be run on Jenkins, you will need to load the CodeQL Jenkins Shared Library into your Jenkins Global Library, or include the CodeQL Jenkins Shared Library in your pipelines dynamically.
If you wish to load the library as a Global Shared Library, you may add the CodeQL Jenkins Shared Library to your Jenkins Global Library by navigating to Manage Jenkins > Configure System > Global Pipeline Libraries
and adding the following library:
- Repository URL:
https://github.com/department-of-veterans-affairs/codeql-tools
- Default version:
main
- Repository path:
- For Linux-based Jenkins pipelines:
jenkins/shared-libraries/linux
- For Windows-based Jenkins pipelines:
jenkins/shared-libraries/windows
- For Linux-based Jenkins pipelines:
If you intend to dynamically load the library instead of adding it as a Global Shared Library, you will need to add the following to the top of a new or exising Jenkinsfile or pipeline:
library identifier: 'codeql-<linux_or_windows>@main', retriever: modernSCM(
scm: [$class: 'GitSCMSource',
remote: 'https://github.com/department-of-veterans-affairs/codeql-tools.git',
credentialsId: '<credential-id>'],
libraryPath: 'jenkins/shared-libraries/<linux_or_windows>')
The remainder of this technical note covers the following topics:
- Using the Shared Library
- Calling the shared library
ExecuteCodeQL
function - Uploading the CodeQL scan results as an artifact
- Example Pipeline With Jenkinsfile Using Global Shared Library
- CodeQL Scan Frequency
Using the Shared Library
The Jenkins Shared Library contains a single function, ExecuteCodeQL
, which will execute the CodeQL scan. The function accepts the following parameters:
org
- The GitHub organization namerepo
- The GitHub repository namebranch
- The branch to scanlanguage
- The language you are scanning, see supported languagesbuildCommand
- The command to build your source code. For compiled languages, this is generally required. For interpreted languages, this is optional.token
- The GitHub Personal Access Token with fullrepo
scope to use for the scan, or a GitHub Fine-Grained Token withcontents: read
andcode-scanning-alerts: read-and-write
permissions, pulled from the Jenkins credentials store. Must be of typeSecret Text
.installCodeQL
- Whether to download CodeQL at runtime, defaults tofalse
Note: You should not reference your GitHub token directly in your pipeline, but instead pull it from the Jenkins credentials store.
To do this, navigate toManage Jenkins > Manage Credentials > System > Global credentials (unrestricted) > Add Credentials
and add a newSecret Text
credential containing your GitHub token. You may then reference the credential in your Jenkinsfile by using thewithCredentials
function.
Calling the shared library ExecuteCodeQL
function
Once you’ve loaded the CodeQL Jenkins Shared Library, running a scan is as simple as calling the ExecuteCodeQL
function in your Jenkinsfile. An example of calling the ExecuteCodeQL
function is as follows:
steps {
checkout scm
withCredentials([string(credentialsId: '<credential-id>', variable: 'TOKEN')]) {
ExecuteCodeQL('<github_org>', '<github_repo>', env.BRANCH_NAME, '<language>', '<build_command>', env.TOKEN, <install_codeql>)
}
}
Note: The
build_command
field must be a single command, it cannot contain ampersand (&
), pipe (|
), or semicolon (;
) characters. If you have a complex build process that requires multiple commands, you may create a script to execute the commands and call the script in thebuild_command
field. If your build must be executed from a specific directory, you may use thedir
orcd
function to change the working directory before executing the build command.
Uploading the CodeQL scan results as an artifact
During the CodeQL scan, the Shared Library will generate a CSV file containing the results of the scan. You may archive the CSV file by using the archiveArtifacts
function. An example of archiving the CSV file is as follows:
archiveArtifacts artifacts: 'codeql-scan-results-<language>.csv', fingerprint: true
Example Pipeline With Jenkinsfile Using Global Shared Library
The below snippet contains a full example of a Jenkinsfile using the CodeQL Jenkins Shared Library as a Global Shared Library to run a CodeQL scan:
@Library('codeql-linux')_
pipeline {
agent { node { label 'linux' } }
stages {
stage('CodeQL - java') {
steps {
checkout scm
withCredentials([string(credentialsId: '<github-pat-credential-id>', variable: 'TOKEN')]) {
ExecuteCodeQL('department-of-veterans-affairs', '<repo-name>', env.BRANCH_NAME, '<codeql-language>', '<build-command>', env.TOKEN, <install-codeql>)
}
archiveArtifacts artifacts: 'codeql-scan-results-<language>.csv', fingerprint: true
}
}
}
post {
always {
cleanWs()
}
}
}
CodeQL Scan Frequency
At a minimum you must scan every eligible language in each of your repositories at least once weekly. You may wish to add additional triggers such as scanning on pull request or on merges to your production branch.
Notice: To remain compliant you must leverage the provided
ExecuteCodeQL
function via the Jenkins Shared Library, which will ensure that the scans are run in compliance with the VA’s code review policy.
Updating CodeQL CLI Bundle
The CodeQL Jenkins Shared Library depends on the CodeQL
CLI being installed on your Jenkins build agents. If you choose to install the CLI yourself in your image, you must ensure you are keeping the CLI up to date. The easiest way to do this is to automate the process of installing the CLI in your image by downloading it using the latest release URL from the CodeQL Action GitHub repository. Once you’ve done this, building your base image on a regular basis will ensure that you are always using the latest version of the CLI.
You may also subscribe to notifications for new releases by navigating to the CodeQL Action GitHub repository in your browser and clicking on the Watch
button in the upper right hand corner of the page. In the Watch
menu, select Custom
and then select Releases
. This will ensure that you are notified of new releases via email.
Return to enable CodeQL using Jenkins CI to continue with the next step.