SonarQube

Code QualityStatic AnalysisSecurityDevOpsContinuous Quality ManagementQuality GatesTechnical Debt

DevOps Tool

SonarQube

Overview

SonarQube is a continuous code quality management platform that uses static analysis to detect bugs, vulnerabilities, and code smells, providing technical debt visualization and automated quality checks through quality gates. Supporting 30+ programming languages with AI-generated code quality assurance capabilities, it's an industry-standard tool that integrates with DevOps pipelines to achieve enterprise-level code quality management and security enhancement.

Details

SonarQube is an enterprise code quality management platform developed by SonarSource, established as the industry standard for static code analysis since its release in 2007. The 2025 version of SonarQube Server 2025.3 introduces AI Code Assurance functionality, enabling automated review and quality checking of AI-generated code.

Key Features

  • Comprehensive Static Analysis: Support for 30+ languages, frameworks, and IaC platforms
  • AI Code Assurance: Automated quality assurance and security checking for AI-generated code
  • Security Enhancement: Comprehensive secret detection and security vulnerability analysis
  • Quality Gates: Prevention of production deployment for code that doesn't meet quality standards
  • Technical Debt Management: Visualization of code debt and improvement prioritization
  • CI/CD Integration: Integration with GitHub Actions, GitLab CI/CD, Azure Pipelines, etc.
  • IDE Integration: Real-time code review through development-time quality checks
  • Compliance Support: Adherence to standards like NIST SSDF, OWASP, CWE, STIG, CASA
  • Multi-Deployment: Support for on-premises, cloud, Docker, and Kubernetes

Provides integrated management of code quality metrics (bugs, vulnerabilities, code smells, duplication, coverage, complexity) to support continuous quality improvement.

Pros and Cons

Pros

  • Centralized enterprise-level comprehensive code quality management
  • AI-generated code quality assurance addresses modern development environments
  • 30+ language support enables unified quality management for multilingual projects
  • Automatic quality standard enforcement through quality gates ensures production quality
  • Technical debt visualization enables planned refactoring
  • Automated quality checks in DevOps pipelines through CI/CD integration
  • Security enhancement through vulnerability and secret detection
  • Compliance-ready quality management meeting regulatory requirements
  • Real-time quality feedback during development through IDE integration
  • Rich metrics and reporting provide numerical basis for quality improvement

Cons

  • Commercial license costs for enterprise features (expensive for large organizations)
  • Complex initial setup and high learning curve
  • Long analysis times for large projects
  • High server resource requirements (CPU, memory, storage)
  • Feature limitations in Community Edition (branch analysis, security features, etc.)
  • Complexity of rule adjustment and customization
  • Operational burden from massive warnings when applying to legacy code
  • Time required for quality culture adoption within development teams
  • Risk of reduced development speed due to excessive quality enforcement

Reference Links

Code Examples

Installation and Setup

Docker Compose Configuration

# docker-compose.yml
version: "3.8"

services:
  sonarqube:
    image: sonarqube:10.8.1-community
    container_name: sonarqube
    depends_on:
      - sonarqube-db
    environment:
      SONAR_JDBC_URL: jdbc:postgresql://sonarqube-db:5432/sonar
      SONAR_JDBC_USERNAME: sonar
      SONAR_JDBC_PASSWORD: sonar
    volumes:
      - sonarqube_data:/opt/sonarqube/data
      - sonarqube_extensions:/opt/sonarqube/extensions
      - sonarqube_logs:/opt/sonarqube/logs
    ports:
      - "9000:9000"
    ulimits:
      nofile:
        soft: 65536
        hard: 65536
      nproc: 4096

  sonarqube-db:
    image: postgres:16-alpine
    container_name: sonarqube-db
    environment:
      POSTGRES_USER: sonar
      POSTGRES_PASSWORD: sonar
      POSTGRES_DB: sonar
    volumes:
      - postgresql_data:/var/lib/postgresql/data

volumes:
  sonarqube_data:
  sonarqube_extensions:
  sonarqube_logs:
  postgresql_data:

Startup and Access

# Start with Docker Compose
docker-compose up -d

# Check logs
docker-compose logs -f sonarqube

# Verify access
curl http://localhost:9000/api/system/health

# Initial access
# URL: http://localhost:9000
# Initial login: admin / admin
# Password change required on first login

Project Analysis Configuration

sonar-project.properties Configuration

# sonar-project.properties - Basic configuration
sonar.projectKey=my-project
sonar.projectName=My Project
sonar.projectVersion=1.0
sonar.sourceEncoding=UTF-8

# Source code configuration
sonar.sources=src
sonar.tests=tests
sonar.exclusions=**/node_modules/**,**/dist/**,**/*.min.js
sonar.test.exclusions=**/node_modules/**

# JavaScript/TypeScript configuration
sonar.javascript.lcov.reportPaths=coverage/lcov.info
sonar.typescript.lcov.reportPaths=coverage/lcov.info

# Java configuration
sonar.java.source=17
sonar.java.target=17
sonar.java.binaries=target/classes
sonar.java.test.binaries=target/test-classes
sonar.junit.reportPaths=target/surefire-reports

# Python configuration
sonar.python.coverage.reportPaths=coverage.xml
sonar.python.xunit.reportPaths=test-results.xml

# C# configuration
sonar.cs.nunit.reportsPaths=TestResults/*.xml
sonar.cs.opencover.reportsPaths=TestResults/coverage.opencover.xml

# Coverage thresholds
sonar.coverage.exclusions=**/*test*/**,**/migrations/**

Analysis Execution with SonarScanner

JavaScript/TypeScript Project

# Install SonarScanner
npm install -g sonar-scanner

# package.json configuration
npm pkg set scripts.sonar="sonar-scanner"

# Run analysis
sonar-scanner \
  -Dsonar.projectKey=my-js-project \
  -Dsonar.sources=src \
  -Dsonar.host.url=http://localhost:9000 \
  -Dsonar.token=your_token_here

# Analysis with coverage
npm run test -- --coverage
sonar-scanner \
  -Dsonar.projectKey=my-js-project \
  -Dsonar.sources=src \
  -Dsonar.tests=src \
  -Dsonar.test.inclusions=**/*.test.ts,**/*.spec.ts \
  -Dsonar.javascript.lcov.reportPaths=coverage/lcov.info \
  -Dsonar.host.url=http://localhost:9000 \
  -Dsonar.token=your_token_here

Maven (Java) Project

<!-- pom.xml -->
<properties>
    <sonar.host.url>http://localhost:9000</sonar.host.url>
    <sonar.token>your_token_here</sonar.token>
    <sonar.coverage.exclusions>
        **/test/**,
        **/target/**
    </sonar.coverage.exclusions>
</properties>

<build>
    <plugins>
        <plugin>
            <groupId>org.sonarsource.scanner.maven</groupId>
            <artifactId>sonar-maven-plugin</artifactId>
            <version>4.0.0.4121</version>
        </plugin>
        
        <plugin>
            <groupId>org.jacoco</groupId>
            <artifactId>jacoco-maven-plugin</artifactId>
            <version>0.8.12</version>
            <executions>
                <execution>
                    <goals>
                        <goal>prepare-agent</goal>
                    </goals>
                </execution>
                <execution>
                    <id>report</id>
                    <phase>test</phase>
                    <goals>
                        <goal>report</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>
# Run Maven analysis
mvn clean compile test jacoco:report sonar:sonar

# Check specific quality gate
mvn sonar:sonar -Dsonar.qualitygate.wait=true

.NET Project

# Install .NET SonarScanner
dotnet tool install --global dotnet-sonarscanner

# Begin analysis
dotnet sonarscanner begin \
  /k:"my-dotnet-project" \
  /d:sonar.host.url="http://localhost:9000" \
  /d:sonar.token="your_token_here" \
  /d:sonar.cs.opencover.reportsPaths="TestResults/coverage.opencover.xml"

# Build and test
dotnet build
dotnet test --collect:"XPlat Code Coverage" -- DataCollectionRunSettings.DataCollectors.DataCollector.Configuration.Format=opencover

# End analysis
dotnet sonarscanner end /d:sonar.token="your_token_here"

CI/CD Integration Examples

GitHub Actions

# .github/workflows/sonarqube.yml
name: SonarQube Analysis

on:
  push:
    branches: [ main, develop ]
  pull_request:
    branches: [ main ]

jobs:
  sonarqube:
    runs-on: ubuntu-latest
    
    steps:
    - name: Checkout code
      uses: actions/checkout@v4
      with:
        fetch-depth: 0  # Shallow clones should be disabled
    
    - name: Setup Node.js
      uses: actions/setup-node@v4
      with:
        node-version: '20'
        cache: 'npm'
    
    - name: Install dependencies
      run: npm ci
    
    - name: Run tests with coverage
      run: npm run test -- --coverage --watchAll=false
    
    - name: SonarQube Scan
      uses: sonarqube-quality-gate-action@master
      env:
        SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
        SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}
      with:
        projectBaseDir: .
        args: >
          -Dsonar.projectKey=${{ github.repository }}
          -Dsonar.sources=src
          -Dsonar.tests=src
          -Dsonar.test.inclusions=**/*.test.ts,**/*.spec.ts
          -Dsonar.javascript.lcov.reportPaths=coverage/lcov.info
    
    - name: Quality Gate Check
      uses: sonarqube-quality-gate-action@master
      timeout-minutes: 5
      env:
        SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
        SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}

GitLab CI/CD

# .gitlab-ci.yml
variables:
  SONAR_USER_HOME: "${CI_PROJECT_DIR}/.sonar"
  GIT_DEPTH: "0"

cache:
  key: "${CI_JOB_NAME}"
  paths:
    - .sonar/cache

stages:
  - test
  - quality

test:
  stage: test
  image: node:20-alpine
  before_script:
    - npm ci
  script:
    - npm run test -- --coverage --watchAll=false
  artifacts:
    reports:
      coverage_report:
        coverage_format: cobertura
        path: coverage/cobertura-coverage.xml
    paths:
      - coverage/
    expire_in: 1 day

sonarqube-check:
  stage: quality
  image: 
    name: sonarsource/sonar-scanner-cli:latest
    entrypoint: [""]
  dependencies:
    - test
  script:
    - sonar-scanner
      -Dsonar.projectKey=${CI_PROJECT_NAME}
      -Dsonar.sources=src
      -Dsonar.tests=src
      -Dsonar.test.inclusions=**/*.test.ts,**/*.spec.ts
      -Dsonar.javascript.lcov.reportPaths=coverage/lcov.info
      -Dsonar.host.url=${SONAR_HOST_URL}
      -Dsonar.token=${SONAR_TOKEN}
      -Dsonar.qualitygate.wait=true
  only:
    - main
    - develop
    - merge_requests

Quality Gate Configuration

Custom Quality Gate Configuration Example

{
  "name": "Strict Quality Gate",
  "conditions": [
    {
      "metric": "new_coverage",
      "operation": "LT",
      "threshold": "80",
      "periodIndex": "1"
    },
    {
      "metric": "new_duplicated_lines_density",
      "operation": "GT",
      "threshold": "3",
      "periodIndex": "1"
    },
    {
      "metric": "new_maintainability_rating",
      "operation": "GT",
      "threshold": "1",
      "periodIndex": "1"
    },
    {
      "metric": "new_reliability_rating",
      "operation": "GT",
      "threshold": "1",
      "periodIndex": "1"
    },
    {
      "metric": "new_security_rating",
      "operation": "GT",
      "threshold": "1",
      "periodIndex": "1"
    },
    {
      "metric": "new_security_hotspots_reviewed",
      "operation": "LT",
      "threshold": "100",
      "periodIndex": "1"
    }
  ]
}

Project-Specific Configuration and Rule Customization

Quality Profile Creation

# SonarQube Web API for Quality Profile operations

# Create new Quality Profile
curl -X POST \
  "${SONAR_HOST_URL}/api/qualityprofiles/create" \
  -H "Authorization: Bearer ${SONAR_TOKEN}" \
  -d "language=js" \
  -d "name=MyCompany TypeScript Rules"

# Add rule
curl -X POST \
  "${SONAR_HOST_URL}/api/qualityprofiles/activate_rule" \
  -H "Authorization: Bearer ${SONAR_TOKEN}" \
  -d "key=MyCompany_TypeScript_Rules" \
  -d "rule=typescript:S1066" \
  -d "severity=MAJOR"

# Change rule configuration
curl -X POST \
  "${SONAR_HOST_URL}/api/qualityprofiles/activate_rule" \
  -H "Authorization: Bearer ${SONAR_TOKEN}" \
  -d "key=MyCompany_TypeScript_Rules" \
  -d "rule=typescript:S3776" \
  -d "severity=CRITICAL" \
  -d "params=threshold=15"

Reports and Metrics Utilization

SonarQube Web API Utilization

# Get project quality metrics
curl -H "Authorization: Bearer ${SONAR_TOKEN}" \
  "${SONAR_HOST_URL}/api/measures/component?component=${PROJECT_KEY}&metricKeys=coverage,duplicated_lines_density,bugs,vulnerabilities,code_smells,sqale_rating,reliability_rating,security_rating"

# Check quality gate status
curl -H "Authorization: Bearer ${SONAR_TOKEN}" \
  "${SONAR_HOST_URL}/api/qualitygates/project_status?projectKey=${PROJECT_KEY}"

# Get issues list
curl -H "Authorization: Bearer ${SONAR_TOKEN}" \
  "${SONAR_HOST_URL}/api/issues/search?componentKeys=${PROJECT_KEY}&types=BUG,VULNERABILITY,CODE_SMELL"

Custom Dashboard Data Collection

# Python example: SonarQube metrics collector
import requests
import json

class SonarQubeCollector:
    def __init__(self, host_url, token):
        self.host_url = host_url
        self.headers = {"Authorization": f"Bearer {token}"}
    
    def get_project_metrics(self, project_key):
        """Get project metrics"""
        metrics = [
            'coverage', 'duplicated_lines_density', 'bugs', 
            'vulnerabilities', 'code_smells', 'sqale_rating',
            'reliability_rating', 'security_rating', 'sqale_index'
        ]
        
        url = f"{self.host_url}/api/measures/component"
        params = {
            'component': project_key,
            'metricKeys': ','.join(metrics)
        }
        
        response = requests.get(url, headers=self.headers, params=params)
        return response.json()
    
    def get_quality_gate_status(self, project_key):
        """Get quality gate status"""
        url = f"{self.host_url}/api/qualitygates/project_status"
        params = {'projectKey': project_key}
        
        response = requests.get(url, headers=self.headers, params=params)
        return response.json()
    
    def get_issues_summary(self, project_key):
        """Get issues summary"""
        url = f"{self.host_url}/api/issues/search"
        params = {
            'componentKeys': project_key,
            'facets': 'types,severities,rules',
            'ps': 1  # Count not needed
        }
        
        response = requests.get(url, headers=self.headers, params=params)
        return response.json()

# Usage example
collector = SonarQubeCollector('http://localhost:9000', 'your_token')
metrics = collector.get_project_metrics('my-project')
quality_gate = collector.get_quality_gate_status('my-project')

Security and Compliance Configuration

Security Hotspot Management

# Get security hotspots list
curl -H "Authorization: Bearer ${SONAR_TOKEN}" \
  "${SONAR_HOST_URL}/api/hotspots/search?projectKey=${PROJECT_KEY}"

# Get hotspot details
curl -H "Authorization: Bearer ${SONAR_TOKEN}" \
  "${SONAR_HOST_URL}/api/hotspots/show?hotspot=${HOTSPOT_KEY}"

# Update hotspot status (reviewed)
curl -X POST \
  -H "Authorization: Bearer ${SONAR_TOKEN}" \
  "${SONAR_HOST_URL}/api/hotspots/change_status" \
  -d "hotspot=${HOTSPOT_KEY}" \
  -d "status=REVIEWED" \
  -d "resolution=SAFE"

Compliance Report Configuration

# compliance-check.yml - Compliance check automation
name: Compliance Check

on:
  schedule:
    - cron: '0 2 * * 1'  # Every Monday at 2 AM
  workflow_dispatch:

jobs:
  compliance:
    runs-on: ubuntu-latest
    steps:
    - name: Generate Compliance Report
      run: |
        # OWASP Top 10 check
        curl -H "Authorization: Bearer ${{ secrets.SONAR_TOKEN }}" \
          "${{ secrets.SONAR_HOST_URL }}/api/measures/component?component=${{ github.repository }}&metricKeys=security_rating,security_hotspots,vulnerabilities" \
          > security-report.json
        
        # CWE category vulnerability aggregation
        curl -H "Authorization: Bearer ${{ secrets.SONAR_TOKEN }}" \
          "${{ secrets.SONAR_HOST_URL }}/api/issues/search?componentKeys=${{ github.repository }}&types=VULNERABILITY&facets=cwe" \
          > cwe-report.json
        
        # Generate report (Python script, etc.)
        python generate-compliance-report.py
    
    - name: Upload Compliance Report
      uses: actions/upload-artifact@v4
      with:
        name: compliance-report
        path: compliance-report.pdf