Happy Dussehra! May good always win. Happy Diwali! Wishing you a bright year ahead. Merry Christmas! Warm wishes from Vizag. Happy New Year! Here’s to a great year ahead.

Archive ยท DevOps

SonarQube: Scanning in CI and Enforcing Quality Gates

Run sonar-scanner from Jenkins and GitLab CI with a token, fail builds on a quality gate, and set sensible gate conditions for new code.

3 min read

  • SonarQube 10.4
  • sonar-scanner 5.0
  • Jenkins 2.440 LTS
  • GitLab CI

An installed SonarQube does nothing until pipelines send code to it. This post wires up scanning, makes the pipeline fail when the quality gate fails, and explains which gate conditions are worth enforcing.

Versions in use on this date. SonarQube 10.4 (6 February 2024), SonarScanner CLI 5.0.x and the Jenkins 2.440 LTS line (first released January 2024) with the SonarQube Scanner plugin. The Community Build analyses one branch, so wire the scan to your main branch and release branches.

Architecture

flowchart TB
  C[Commit to main] --> CI[Jenkins or GitLab CI job]
  CI --> T[Build and unit tests<br/>coverage report]
  T --> SC[sonar-scanner<br/>sends analysis report]
  SC -->|HTTPS with token| SQ[SonarQube server]
  SQ --> CE[Compute Engine<br/>processes report]
  CE --> QG{Quality gate}
  QG -->|passed| NEXT[Deploy stages continue]
  QG -->|failed| FAIL[Build fails and team notified]
  SQ -.->|webhook result| CI

Analysis is asynchronous: the scanner uploads a report and finishes, then the server computes the result. The pipeline must wait for that result, otherwise the gate is never enforced.

Project settings and token

Create a project, then generate a project analysis token (My Account, Security, or a project-scoped token). Store it as a CI secret and never in the repository. sonar-project.properties:

sonar.projectKey=shop-api
sonar.projectName=Shop API
sonar.sources=src
sonar.tests=test
sonar.exclusions=**/node_modules/**,**/*.spec.js
sonar.javascript.lcov.reportPaths=coverage/lcov.info
sonar.qualitygate.wait=true
sonar.qualitygate.timeout=300

With sonar.qualitygate.wait=true the scanner polls and exits non-zero when the gate fails, which is the simplest way to enforce it.

Jenkins pipeline

Configure the server under Manage Jenkins, System, SonarQube servers with the token as a credential, and add a webhook in SonarQube (Administration, Configuration, Webhooks) pointing to https://jenkins.example.com/sonarqube-webhook/.

pipeline {
  agent any
  tools { nodejs 'node20' }
  stages {
    stage('Test') { steps { sh 'npm ci && npm test -- --coverage' } }
    stage('Sonar') {
      steps {
        withSonarQubeEnv('sonar-prod') {
          sh 'npx sonarqube-scanner'
        }
      }
    }
    stage('Quality Gate') {
      steps {
        timeout(time: 10, unit: 'MINUTES') {
          waitForQualityGate abortPipeline: true
        }
      }
    }
  }
}

GitLab CI equivalent

sonar:
  stage: test
  image: sonarsource/sonar-scanner-cli:5.0
  variables:
    SONAR_HOST_URL: https://sonar.example.com
    GIT_DEPTH: "0"
  script:
    - sonar-scanner -Dsonar.token=$SONAR_TOKEN -Dsonar.qualitygate.wait=true
  rules:
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH

GIT_DEPTH: "0" fetches full history, which SonarQube needs to attribute new code and blame information.

Designing the quality gate

The built-in Sonar way gate applies to new code, not the whole legacy codebase, so a project with old debt can still pass. This is the Clean as You Code approach.

Condition (on new code) Typical threshold
Coverage 80% or higher
Duplicated lines 3% or lower
Maintainability, reliability and security ratings A
Security hotspots reviewed 100%

Define the new code period (for example, since the last release or the previous 30 days) so the gate judges recent changes fairly. Start with the defaults, fix what blocks, then tighten slowly; an unreachable gate gets ignored.

Operations

  • Use a service account for tokens, rotate them, and revoke the token of anyone who leaves.
  • Quality Profiles control the rules; copy the built-in profile before changing it, so updates do not overwrite your edits.
  • Failed analysis with a memory error on large projects: raise the scanner heap with SONAR_SCANNER_OPTS=-Xmx2g.
  • If the pipeline hangs on the gate, the webhook is not reachable: check the Jenkins URL and the webhook delivery log in SonarQube.