CodeSonar analysis in a GitLab pipeline on Linux with Docker
The following instructions are for Linux containers using Docker.
We provide separate instructions for other environments:
These instructions assume you are using CodeSonar 7.3 or later,
where the codesonar analyze -remote-archive
option is supported.
- These instructions are also suitable for use with CodeSonar 7.2 and 7.1, provided that your hub has one or more associated remote analysis launch daemons that you can use to perform remote-managed analyses (with
codesonar analyze -remote
).
Prerequisites
These instructions assume that you have satisfied the prerequisites as described in the setup overview document.
In particular, make sure you have access to the following.
- A CodeSonar hub.
- A GitLab server.
- A machine suitable for setting up a container image for a "CI builder".
- Unless you are using CodeSonar SaaS, or your hub already has suitable associated remote analysis launch daemons, a machine suitable for setting up and running a container image for an "analysis data server". This can be the same as the machine for the "CI builder", but does not have to be.
Overview
- A. Prepare an example project (zlib)
- B. Create and install an analysis data server
- C. Create and install a pipeline build runner
- D. Create a basic pipeline that can build your code
- E. Install CodeSonar and integration tools in CI builder environment
- F. Update the pipeline job definition to perform CodeSonar analysis
A. Prepare an example project (zlib)
For the sake of an easy but realistic example, we will assume you want to build and analyze zlib v1.2.13: https://github.com/madler/zlib.
Prepare the example repository on your GitLab server as follows.
On your developer workstation, clone the zlib repository.
git clone https://github.com/madler/zlib
Create a new repository project named "zlib" (or similar) in your GitLab server instance with the following properties:
- Empty ("blank") repository.
- Private or Internal visibility (not public).
- Do not initialize with a README.
- Enable Static Application Security Testing (SAST) (if available).
Follow the instructions provided by the GitLab repository project page to "push an existing Git repository" in order to push your local zlib repository clone to your GitLab server.
After following the GitLab instructions, your local zlib repository should be configured so that its "origin" is on your GitLab server, and not the original GitHub.com location.
You should now have an example zlib project in your GitLab server which you can build and analyze in the steps that follow.
The instructions in this document were tested with zlib v1.2.13. You can "check out" v1.2.13 by creating a branch for the Git tag 'v1.2.13' and checking out the branch:
git branch example v1.2.13
git checkout example
B. Create and install an analysis data server
NOTE If you plan to analyze your code using a remote-managed or SaaS analysis service, then you do not need to install an analysis data server. Go on to C. Create and install a pipeline build runner.
Otherwise, set up an analysis data server now.
C. Create and install a pipeline build runner
If needed, create a CodeSonar CI hub user.
You will need a CodeSonar hub user account that can be used for automated pipeline jobs. If you previously created a hub user for an analysis data server, then you can use that account here too. Otherwise, create a new hub user account.
The remainder of these instructions will assume that the hub user name is cshub_ci.
If you have not already done so, identify a suitable CI builder host machine.
This "CI builder" machine is distinct from the "analysis data server" machine prepared previously, however it is possible to use the same machine for both analysis data server and CI builder.
- This can be a physical machine or a virtual machine.
Log in to your CI builder machine as
root
.If it is not already installed, use your package manager to install Docker Engine.
See https://docs.docker.com/engine/install/#server for more information
If GitLab Runner is not already installed, install and register a GitLab Runner container.
(If you prefer, you can run a GitLab Runner instance directly on the builder host machine. These instructions assume that you want to run it in a container. If the runner runs in a container, then it will start pipeline job containers using a "bind-mounted docker socket".)
Instructions for configuring a GitLab Runner for Docker-based pipelines that itself runs inside a Docker container will be provided below. See the GitLab documentation for additional information:
- Runner installation: https://docs.gitlab.com/runner/install/index.html
- Runner installation in a container: https://docs.gitlab.com/runner/install/docker.html
- Runner configuration: https://docs.gitlab.com/runner/executors/docker.html.
- Runner FAQ: https://docs.gitlab.com/runner/faq/index.html.
To create and initialize the runner container, do the following.
Get a GitLab Runner registration token from the "CI/CD" Runner settings page on your GitLab instance.
Note that you can register a runner at the project, group, or global level.
Set up variables.
CI_RUNNER_NAME=gitlab-runner CI_RUNNER_VOL=$CI_RUNNER_NAME.config CI_RUNNER_CONTAINER=$CI_RUNNER_NAME
Create a Docker volume to save runner configuration files. The data in this volume will be persisted even when the container stops.
docker volume create $CI_RUNNER_VOL
Start the runner as a restartable background process: this will initialize the configuration in the configuration volume.
docker run \ --detach \ --restart unless-stopped \ --name $CI_RUNNER_CONTAINER \ -v /var/run/docker.sock:/var/run/docker.sock \ -v $CI_RUNNER_VOL:/etc/gitlab-runner \ gitlab/gitlab-runner:latest
Register the runner using a temporary container.
docker run --rm -it \ -v $CI_RUNNER_VOL:/etc/gitlab-runner \ gitlab/gitlab-runner:latest register
You will be prompted to provide runner registration information.
- Registration token: enter the runner registration token you obtained from your GitLab server instance.
- Tags:
Linux
,Docker
. These tags will help ensure your pipeline jobs execute on the correct runner. - Executor:
docker
.
This will update the runner configuration volume with runner registration information.
Restart the background runner so that it will read the new configuration.
docker restart $CI_RUNNER_CONTAINER
Log out of the CI builder machine.
D. Create a basic pipeline that can build your code
To start, we must define a pipeline job that can build the code.
The pipeline definition is specified in a .gitlab-ci.yml
file in the root of your code repository.
For information about the .gitlab-ci.yml
file, see
https://docs.gitlab.com/ee/ci/yaml/gitlab_ci_yaml.html.
If you are not familiar with YAML format, you may want to read about it at https://yaml.org/spec/1.2/spec.html#Preview. Note that YAML is very sensitive to indentation.
You don't need to be logged in to your runner machine to create pipeline job images.
The steps below should be carried out from your developer workstation.
Create a Docker image for building your code.
Create an empty directory named "zlib.build".
The zlib.build directory can exist anywhere on disk. It could be saved in the Git repository, but we will not assume so in this example.
Save the content below to a file named "Dockerfile" in the "zlib.build" directory.
FROM ubuntu:18.04 RUN apt-get update && apt-get install -y git gcc make
Change to the zlib.build directory.
cd zlib.build
Execute the following commands to build the image and push it to the GitLab Docker registry. The CI builder runner will be able to download images from the Docker registry.
Make any necessary changes to variable settings before executing.
Variable Setting CI_REGISTRY
The address of your Docker registry: typically the host name of your GitLab server plus port 5050. CI_REGISTRY_IMAGE
The fully-qualified Docker image name. This will include the name of the Docker registry where it is found (in this case, CI_REGISTRY
).CI_IMAGE_VERSION
A Docker image tag which indicates the version of the image. CI_REGISTRY=gitlab.example.com:5050 CI_REGISTRY_IMAGE=$CI_REGISTRY/group/project CI_IMAGE_VERSION=latest docker login $CI_REGISTRY docker build -t $CI_REGISTRY_IMAGE:$CI_IMAGE_VERSION - < Dockerfile docker push $CI_REGISTRY_IMAGE:$CI_IMAGE_VERSION
Create a new file named ".gitlab-ci.yml" and save it in your local repository clone.
Insert the following content into .gitlab-ci.yml.
workflow: rules: - if: $CI_MERGE_REQUEST_IID - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH stages: - build build: stage: build tags: - Linux - Docker image: $CI_REGISTRY_IMAGE:latest script: - ./configure - make all
Create a repository branch named "ci/main" (or whatever else you prefer) where you can save your pipeline definition.
git checkout -b ci/main git add .gitlab-ci.yml
Commit and push your
.gitlab-ci.yml
file to your GitLab server.git commit -m "Add gitlab-ci configuration" git push -u origin ci/main
Test the pipeline.
Create a merge request for the branch you just pushed.
The
git push
command from the previous step may print a URL to help you create a merge request. You can also use the GitLab GUI directly to create a new merge request associated with your new branch. When you create a new merge request for your new branch, GitLab will notice the pipeline definition file and will use it to execute a pipeline on your CI builder machine.Verify that the pipeline executed successfully.
Use the GitLab "Merge request" web page to find your pipeline status. If everything works correctly, you should see that your pipeline executed and if you inspect the job log, you should see that the code was successfully compiled.
E. Install CodeSonar and integration tools in CI builder environment
At this stage, you should have a working pipeline that compiles your code. The next task is to install CodeSonar tools on your CI builder machine so that you can execute a CodeSonar analysis.
Log in to your CI builder machine as
root
.Download and extract the CodeSonar-GitLab Integration tools.
- Download the CodeSonar-GitLab integration tools package (e.g.
codesonar-gitlab-integration-1.6p0.tar.gz
). - Extract the package.
cd /opt tar -xzf /path/to/codesonar-gitlab-integration-1.6p0.tar.gz
- Download the CodeSonar-GitLab integration tools package (e.g.
Change to the
distro-image
subdirectory in the extracted CodeSonar GitLab integration files.Inspect the contents. There should be a
Dockerfile
: this can be used to create a new Docker image from your project's base image with CodeSonar added to it.Copy your CodeSonar software installation file into the
distro-image
subdirectory. The name will be something likecodesonar-7.3p0.20230330-x86_64-pc-linux.tar.gz
(version number and datestamp will vary).[HTTPS hubs only] Download a copy of your hub's hub server certificate. We will use this copy to ensure that the CodeSonar command line tools in your Docker image will trust your hub.
If your CodeSonar hub uses plain HTTP (and not secure HTTPS), skip this step.
Otherwise:
Download the hub server certificate from the hub Configure HTTPS page.
See the Troubleshooting document for additional information about how to download this file.
Save the certificate in Base-64 ASCII text format (often called "PEM" format) as
distro-image/cacert.pem
.
Build a new CodeSonar Docker image using
distro-image/Dockerfile
.This new CodeSonar Docker image will be based on your project's builder Docker image. It will be used to introduce CodeSonar into your pipeline. This will allow CodeSonar to observe and analyze your code as it builds.
Consult the comments in
distro-image/Dockerfile
for descriptions of the Docker build arguments used in this section. Many of the build arguments used here are optional and are intended to reduce the size of the Docker image. In particular, zlib contains no Java code so we omit all the components used for Java analysis. If you want Java (or .NET) analysis, then remove--buildarg JAVA_ANALYSIS=0
from the command below.Make any necessary changes to variable settings before executing. Note that some of the variables used here were initialized in previous steps.
Variable Setting CI_REGISTRY
,CI_REGISTRY_IMAGE
,CI_IMAGE_VERSION
Must have exactly the same values as were used to create the builder image. CODESONAR_PACKAGE
The name of the CodeSonar installer file that you copied to distro-image
CI_REGISTRY=gitlab.example.com:5050 CI_REGISTRY_IMAGE=$CI_REGISTRY/group/project CI_IMAGE_VERSION=latest CODESONAR_PACKAGE=codesonar-7.3p0.20230330-x86_64-pc-linux.tar.gz CODESONAR_IMAGE=$CI_REGISTRY_IMAGE/codesonar CODESONAR_IMAGE_VERSION=$CI_IMAGE_VERSION docker build --tag $CODESONAR_IMAGE:$CODESONAR_IMAGE_VERSION \ --build-arg BASE_IMAGE=$CI_REGISTRY_IMAGE:$CI_IMAGE_VERSION \ --build-arg CODESONAR_PACKAGE=$CODESONAR_PACKAGE \ --build-arg CODESONAR_HUB_CACERT=cacert.pem \ --build-arg TELEMETRY=1 \ --build-arg HUB=0 \ --build-arg JAVA_ANALYSIS=0 \ --build-arg PYTHON_ANALYSIS=0 \ --build-arg JAVA_API=0 \ --build-arg CSHARP_API=0 \ --build-arg ECLIPSE=0 \ .
Push the new CodeSonar Docker image to your container registry:
docker login $CI_REGISTRY docker push $CODESONAR_IMAGE:$CODESONAR_IMAGE_VERSION
F. Update the pipeline job definition to perform CodeSonar analysis
Most of the steps that follow should be performed in your local example (zlib) repository on your developer workstation.
Generate a CodeSonar hub user certificate and key.
- If you already have a suitable hub user certificate and private key, you do not need to generate new ones.
When you set up
CODESONAR_HUB_USER_CERT_FILE
andCODESONAR_HUB_USER_KEY_FILE
later, use your existing files. Go on to the next step.
In this example we will configure the workflow to perform certificate-based hub authentication.
If you cannot use certificate-based authentication (for example, because your hub is not configured for HTTPS), skip this step: you will modify the authentication-related command elements in later steps.
Certificate generation requires the CodeSonar command line tools. If you don't have CodeSonar installed on your developer workstation, install it before proceeding. Alternatively, you could start a shell in a temporary Docker container on the CodeSonar analysis image that you built in part E and use the CodeSonar command line tools there.
Start a new container using your CodeSonar Docker image, and open an interactive bash shell prompt.
CI_REGISTRY=gitlab.example.com:5050 CI_REGISTRY_IMAGE=$CI_REGISTRY/group/project CI_IMAGE_VERSION=latest CODESONAR_IMAGE=$CI_REGISTRY_IMAGE/codesonar CODESONAR_IMAGE_VERSION=latest docker run -it "$CODESONAR_IMAGE:$CODESONAR_IMAGE_VERSION" bash
Execute the following. Make any necessary changes to variable settings before executing.
Variable Setting CSONAR
Your CodeSonar installation. CSONAR_HUB
Your hub location. CSONAR_HUBUSER
Your hub user account. Note that the command below uses this as both the username of the account that is authorizing certificate generation and the username of the account that is the subject of the certificate. CSONAR=/opt/codesonar CSONAR_HUB=https://codesonar.example.com:7340 CSONAR_HUBUSER=cshub_ci CSONAR_HUBCERT=$CSONAR_HUBUSER.cert CSONAR_HUBKEY=$CSONAR_HUBUSER.key $CSONAR/codesonar/bin/codesonar generate-hub-cert \ -foruser "$CSONAR_HUBUSER" \ -auth password \ -hubuser "$CSONAR_HUBUSER" \ -out "$CSONAR_HUBCERT" \ -outkey "$CSONAR_HUBKEY" \ "$CSONAR_HUB"
Provide the hub user account password when prompted.
New files
$CSONAR_HUBUSER.cert
and$CSONAR_HUBUSER.key
will be created, where$CSONAR_HUBUSER
is the name of your hub CI user account. These files contain your certificate and private key, respectively.You can use the standard
cat
command to show the contents of the certificate and/or key files as needed.Copy these two files and save them somewhere temporarily.
Exit the bash shell and the container.
exit
- If you already have a suitable hub user certificate and private key, you do not need to generate new ones.
When you set up
Download a copy of your GitLab server's HTTPS root certificate.
In some cases, CodeSonar's Python interpreter will refuse to communicate with your GitLab server since it does not trust your GitLab server's HTTPS certificate. This may happen if your GitLab server uses a recently-issued certificate. In order to avoid a potential problem later, you can provide a copy of the certificate to CodeSonar in your pipeline configuration.
- Download a copy of the root authority certificate for your GitLab Server's HTTPS certificate.
- Save this root certificate to your repository working directory in Base-64 ASCII text format (often called "PEM" format).
See the "Troubleshooting" document for additional information about how to download this file. We will assume you have saved the root certificate file to the root of your local repository with the name "gitlab.root.cacert".
Configure your CI/CD pipeline to use CodeSonar.
Modify your
.gitlab-ci.yml
file to add a codesonar-sast job, using the example below as a template. (Note that some GitLab features will assume that your "SAST scanning" job name is suffixed with "-sast".)This example makes use of many environment variables.
- Some of the variables are Predefined by GitLab.
- Other variables are defined in the pipeline definition itself.
- Still others are defined in your GitLab project settings as custom "CI/CD Variables" (a full list is provided in the next step).
For more information see: https://docs.gitlab.com/ee/ci/variables/.
Make the following changes to the example.
- Ensure that the
tags
for each job match the runner that the job requires. - Update the
image
keywords to refer to the "CI builder" and "CodeSonar" Docker images you created earlier. - Update the
SARIF2SAST
,CODESONAR
, andCSPYTHON
variables so that they refer to the correct locations. - Update the
CI_SERVER_CAFILE
variable if necessary so that it refers to your GitLab Server's HTTPS root authority certificate file. - Be sure to add the
test
item under thestages
section of the YAML file. For CodeSonar SaaS or other remote-managed analysis, replace
-remote-archive "${CODESONAR_REMOTE_LAUNCHDS}"
with
-remote "${CODESONAR_REMOTE_LAUNCHDS}"
To provide a different name for your analysis, modify the
-name
value.For password-based authentication, replace each occurrence of
-auth certificate -hubcert "$CODESONAR_HUB_USER_CERT_FILE" -hubkey "$CODESONAR_HUB_USER_KEY_FILE"
with
-auth password -hubuser "${CODESONAR_HUBUSER}" -hubpwfile ${CODESONAR_HUBPWFILE}
(note that there are multiple occurrences).
The
-property
arguments are used for adding additional, searchable data to your CodeSonar analysis. They are included here since they are often helpful for searching for analyses related to specific code commits. You may want to add more-property
arguments in order to retain more searchable data for the analysis.
For full details of the
codesonar analyze
command, see the CodeSonar manual: Using CodeSonar > Building and Analyzing Projects > Command Line Build/AnalysisExample:
workflow: rules: - if: $CI_MERGE_REQUEST_IID - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH stages: - build - test build: stage: build tags: - Linux - Docker image: $CI_REGISTRY_IMAGE:latest script: - ./configure - make all codesonar-sast: stage: test tags: - Linux - Docker image: $CI_REGISTRY_IMAGE/codesonar:latest variables: SARIF2SAST: "/opt/codesonar-sarif2sast" CODESONAR: "/opt/codesonar/codesonar/bin/codesonar" CSPYTHON: "/opt/codesonar/codesonar/bin/cspython" CODESONAR_PROJECT_NAME: "$CI_PROJECT_NAME" CI_SERVER_CAFILE: "gitlab.root.cacert" script: - ./configure - > $CODESONAR analyze "${CODESONAR_PROJECT_NAME}" -wait -remote-archive "${CODESONAR_REMOTE_LAUNCHDS}" -auth certificate -hubcert "$CODESONAR_HUB_USER_CERT_FILE" -hubkey "$CODESONAR_HUB_USER_KEY_FILE" -name "gitlab-ci ref=${CI_COMMIT_REF_NAME} update=${CI_MERGE_REQUEST_IID} job=${CI_PIPELINE_ID}.${CI_JOB_ID} commit=${CI_COMMIT_SHORT_SHA}" -property branch "$CI_COMMIT_REF_NAME" -property commit "$CI_COMMIT_SHORT_SHA" -property os "$CI_RUNNER_EXECUTABLE_ARCH" -property ci-job "$CI_JOB_ID" -property ci-run "$CI_PIPELINE_ID" -property merge-request "$CI_MERGE_REQUEST_IID" "${CODESONAR_HUB_URL}" make all |& tee analysis.log - CODESONAR_ANALYSIS_ID=$($CSPYTHON $SARIF2SAST/analysis_id.py "${CODESONAR_PROJECT_NAME}") - > $CODESONAR get -auth certificate -hubcert "$CODESONAR_HUB_USER_CERT_FILE" -hubkey "$CODESONAR_HUB_USER_KEY_FILE" -o allwarnings.sarif "${CODESONAR_HUB_URL}/analysis/${CODESONAR_ANALYSIS_ID}-allwarnings.sarif?filter=\"${CODESONAR_VISIBILITY_FILTER}\"" - > $CSPYTHON $SARIF2SAST/sarif2sast.py --sarif allwarnings.sarif --output gl-sast-report.json --summary-report sast-summary-report.md --codesonar-url "${CODESONAR_HUB_URL}" --analysis-id ${CODESONAR_ANALYSIS_ID} --max ${CODESONAR_MAX_WARNINGS} --threshold ${CODESONAR_WARNING_THRESHOLD} after_script: - > $CSPYTHON $SARIF2SAST/upload_gitlab_mr_notes.py --api-token-variable GITLAB_TOKEN --report sast-summary-report.md --cafile "${CI_SERVER_CAFILE}" artifacts: reports: sast: gl-sast-report.json
Use the GitLab UI to add all the custom variables used by the .yml file to your GitLab project. These settings are available from your GitLab project page: Settings > CI/CD > Variables.
Note that these variables are shared by all pipelines in your repository project. They will therefore apply to all pipelines triggered by all merge requests on the repository.
- When creating these variables, uncheck the "Protect variable" option. "Protected" variables can only be used on "protected" branches, and merge request branches will not typically be protected.
- Check the "Mask variable" option for sensitive variables such as
GITLAB_TOKEN
. - Note that some of these must be configured as a File-type variables.
- Consider using a restricted user account for the the hub user and for any GitLab user associated with the
GITLAB_TOKEN
.
Some of these variables contain sensitive information that must be secured.
Type Key Example value Notes Variable CODESONAR_HUB_URL
https://codesonar.example.com:7340 Variable CODESONAR_REMOTE_LAUNCHDS
/analysis-data-server/* Specifies a remote launch daemon to manage your analysis data after the analysis phase is complete. If your codesonar analyze
command specifies-remote
instead ofremote-archive
, the launch daemon will also manage the analysis phase, otherwise it will be managed locally. For CodeSonar SaaS, set to/saas/*
. If you set up an analysis data server in part B, set to/analysis-data-server/*
(assuming you created a launchd group with path/analysis-data-server
).File CODESONAR_HUB_USER_CERT_FILE
-----BEGIN CERTIFICATE-----\nMIIEabcdefghi ...
For certificate-based authentication only: the contents of the hub user certificate file that you generated above. You do not need to escape newline characters when entering the secret value in the CI/CD variable value form. The '\n' characters in the example are not intended to be copied literally. File CODESONAR_HUB_USER_KEY_FILE
-----BEGIN PRIVATE KEY-----\nMIIEjklmnopqr ...
For certificate-based authentication only: the contents of the hub user certificate private key file that you generated above. You do not need to escape newline characters when entering the secret value in the CI/CD variable value form. The '\n' characters in the example are not intended to be copied literally. Variable CODESONAR_HUBUSER
cshub_ci For password-based authentication only. File CODESONAR_HUBPWFILE
p@55W0Rd For password-based authentication only. Variable CODESONAR_MAX_WARNINGS
5 The pipeline is configured to fail if there are more than CODESONAR_MAX_WARNINGS
warnings with score exceedingCODESONAR_WARNING_THRESHOLD
. This provides you with a simple means to alert developers to new, significant warnings affecting their code.Variable CODESONAR_VISIBILITY_FILTER
active Only warnings satisfying this filter will be evaluated for threshold comparison (as described for CODESONAR_MAX_WARNINGS
) and for the GitLab security report. A factory default filter such as "all" or "active" is typical, but you can use the name of any saved search available to your hub user. CodeSonar 6.0 and earlier require the filter to be specified as a numeric ID.Variable CODESONAR_WARNING_THRESHOLD
70 See CODESONAR_MAX_WARNINGS
.Variable GITLAB_TOKEN
BSDrHhFPWJkq3F9w5kfy Used to automatically generate a merge request comment containing a summary of the CodeSonar analysis. To use this feature, you will need to generate a GitLab API Access Token. GitLab provides several ways to do this. A Project Access Token is likely the best option, see: https://docs.gitlab.com/ee/user/project/settings/project_access_tokens.html. The Access Token will need full "api" (read and write) access. Create a new branch.
For example, if you decide to name your branch "ci/codesonar":
git checkout -b ci/codesonar
Add and commit your updated files to your Git repository and push the changes to GitLab.
If you need to add the GitLab server certificate file to your repository, you should do that here too.
For example:
git add .gitlab-ci.yml gitlab.root.cacert git commit -m "Add CodeSonar pipeline job" git push -u origin ci/codesonar
Follow GitLab instructions to create a merge request for your new branch.
When the pipeline completes, you should see "Security scanning" results on the merge request "Overview" page.
Click the "View full report" button to see the analysis results.
Notice that the results shown in the "full report" are associated with a pipeline.
The analysis report will include hyperlinks to your CodeSonar hub.