SonarQube is a well known, high quality tool utilized by many prominent companies such as Audible, Porsche, Bosch, and HP for advanced code analysis. However, you can easily use it for free to see what can be done to improve project security and reduce maintenance costs. One way to do that is to install a local copy on your development environment.
I’m going to set up a SonarQube service in a Docker container. I’ll explain the configuration that I used and include links to the documentation. Next, I’ll run an example SonarQube code analysis on one of my projects using the maven verify phase (though you can change which phase to use). Finally, I’ll show you how to share custom profiles with other developers so that everyone can analyse code according to the same principles.
You’ll find an example Spring Boot project that uses the SonarQube instance described in this post (locally) and SonarCloud (in Github Workflows) in the efficient-mvp-example repository on Github.
We’re going to use the official SonarQube image. In this example I’m going to run it with Docker Compose and the SonarQube v8.4.1-community image.
I want to keep my container configurable and allow users of the docker-compose file to run whichever version they choose. Therefore, I’m going to keep the default version as an environment variable in an .env
file:
# sonarqube/.env
SONAR_VERSION=8.4.1-community
Below you’ll find the complete docker-compose.yml
file based on the recommendation given in the image description:
# sonarqube/docker-compose.yml
version: "3.3"
services:
sonarqube:
image: sonarqube:$SONAR_VERSION
ports:
- "9000:9000"
networks:
- internal
volumes:
- sonarqube_data:/opt/sonarqube/data
- sonarqube_extensions:/opt/sonarqube/extensions
restart: unless-stopped
stop_grace_period: 5m
networks:
internal:
volumes:
sonarqube_data:
sonarqube_extensions:
I want to preserve analysis data even after the SonarQube container is deleted. For this reason I instantiated the sonarqube_data
volume. It will hold the embedded H2 database and Elasticsearch indexes. Furthermore, I added the sonarqube_extensions
volume in case I want to add some plugins later.
I use this service on a daily basis. Therefore, I want it to restart automatically every time I turn on my computer. You can omit this setting if you want to keep the default policy and run the service manually.
By default, Docker will wait 10 seconds when trying to stop a container. SonarQube recommends configuring the service to wait for any tasks in progress to finish in order to avoid hard termination. I set the stop_grace_period to 5 minutes.
By default, SonarQube is configured to accept admin
as both the username and password. In the long run, you may want to specify your own credentials. In order to achieve it, use the environment variables provided with the image: SONARQUBE_USERNAME and SONARQUBE_PASSWORD. Include them in your docker-compose.yml
file. Furthermore, you can add your default values to the .env
file. In my case though, I’m going to use the original credentials.
Without further ado, start the container with the $ docker-compose up -d
command. You can verify the state of the service with the $ docker ps
command. The result is visible on the image below:
Finally, visit http://localhost:9000/ to see the SonarQube welcome screen:
Next, use the default credentials to login (if you didn’t override them):
admin
admin
As a result, you’ll be greeted with the SonarQube dashboard ready to be filled with code analysis data:
I wanted to include a test coverage report in my analysis. Therefore, I created the code-coverage
profile and added the JaCoCo plugin to my pom.xml
file:
<!-- pom.xml -->
…
<properties>
<jacoco.version>0.8.5</jacoco.version>
</properties>
…
<profiles>
<!-- Code coverage report generation -->
<profile>
<id>code-coverage</id>
<properties>
<env>test</env>
<gebEnv>test</gebEnv>
<jacoco.skip>false</jacoco.skip>
<maven.test.skip>false</maven.test.skip>
<skip.unit.tests>false</skip.unit.tests>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>${jacoco.version}</version>
<executions>
<execution>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>report</id>
<phase>post-integration-test</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
</plugin>
</plugins>
</build>
<reporting>
<plugins>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>${jacoco.version}</version>
</plugin>
</plugins>
</reporting>
</profile>
</profiles>
Additionally, I added Maven Failsafe Plugin to include my integration tests in the report.
A straightforward way of examining the code is to run the following command (*) in the project directory:
$ mvn clean verify sonar:sonar -Pcode-coverage
(*) Edit: For newer docker images of SonarQube you’ll need to provide your credentials as well:
$ mvn clean verify sonar:sonar -Pcode-coverage -Dsonar.login=your_login -Dsonar.password=your_password
After a successful analysis you can see your project under the http://localhost:9000/projects link:
I activated over 450 rules in my custom profile to get a more strict review of my code. You can see the detailed result below:
To sum up, the sooner you include SonarQube analysis in the code development cycle, the shorter the technical debt is going to be. Be sure that all team members use the same Quality Profile
and run analysis before every commit to ensure that they didn’t introduce any vulnerabilities – the New Code
section should be devoid of warnings. In the meantime, you can always refactor some of the existing code or add tests to enhance the ratings.
As we can read in SonarQube docs:
If SonarQube’s results aren’t relevant, no one will want to use it. That’s why precisely configuring what to analyze for each project is a very important step. Doing so allows you to remove noise, like the issues and duplications marked on generated code, or the issues from rules that aren’t relevant for certain types of files.
Narrowing the Focus
If you don’t want some classes in code coverage reports, e.g. all classes that ends with Config.java
, you can use the <sonar.exclusions>
property:
<profile>
<id>code-coverage</id>
<properties>
…
<sonar.exclusions>**/*Config.java</sonar.exclusions>
</properties>
…
</profile>
An example of the code that we don’t want to analyze at all is the code generated with Lombok. Add the src/lombok.config
file with the following content:
lombok.addLombokGeneratedAnnotation = true
With the original configuration, SonarQube conducts code analysis according to the default set of rules. You can familiarize yourself with them by visiting http://localhost:9000/profiles:
Click the Sonar way
for the language you’re interested in and browse the active rules. For instance, when browsing Java rules, you can see that there are 397 active guidelines that will be used when analysing your code:
Once you get to know them, you can adjust the profile according to your needs. As we can read in the SonarQube documentation:
The Sonar way Quality Profiles are a good starting-point as you begin analyzing code, and they start out as the default Quality Profiles for each language. That being said, we recommend that you Copy this profile and begin to fine-tune the contents. Why?
– Default Quality Profiles are not editable, so you won’t be able to customize the Sonar way to your needs
https://docs.sonarqube.org/latest/instance-administration/quality-profiles/
– The Sonar way becomes a baseline against which you can track your own Quality Profiles
– The Sonar way may be updated over time to adjust which rules are included and adjust rule severities.
Go back to http://localhost:9000/profiles and copy the profile you want to customize:
As you can see, the Activate more
option is available on your copy:
Finally, you can browse additional rules and decide which of them to activate:
It’s important that all developers working on a particular project use the same set of SonarQube rules. For this reason, back up
your profile and save it as an xml
document:
Consequently, all team members can now import your profile on their instances of SonarQube:
Last but not least, make sure to set it as the default profile.
E
grade under the Security Report
.Maintainability Overview
report shows extremely helpful information, such as which classes to prioritise when tackling technical debt:Photo by Retha Ferguson from Pexels
Spring Security allows us to use role-based control to restrict access to API resources. However,…
A custom annotation in Spring Boot tests is an easy and flexible way to provide…
Delegating user management to Keycloak allows us to better focus on meeting the business needs…
Swagger offers various methods to authorize requests to our Keycloak secured API. I'll show you…
Configuring our Spring Boot API to use Keycloak as an authentication and authorization server can…
Keycloak provides simple integration with Spring applications. As a result, we can easily configure our…