SonarQube Code Qualität und Sicherheit Plattform Cheat Blatt
Überblick
SonarQube ist eine umfassende Plattform zur kontinuierlichen Überprüfung von Codequalität und Sicherheit. Es führt automatische Bewertungen mit statischer Analyse von Code, um Fehler, Codegeruch und Sicherheitslücken über 25+ Programmiersprachen zu erkennen. Sonar Qube ist in DevSecOps-Pipelines für die Einhaltung von Code-Qualitätsstandards und die Identifizierung von Sicherheitsfragen früh im Entwicklungslebenszyklus unerlässlich.
ZEIT Note: SonarQube erfordert eine richtige Konfiguration und Regelanpassung für optimale Ergebnisse. Es sollte in CI/CD-Pipelines zur kontinuierlichen Überwachung integriert werden.
Installation
Docker Installation (empfohlen)
```bash
Pull SonarQube image
docker pull sonarqube:community
Run SonarQube with PostgreSQL
docker run -d --name sonarqube \ -p 9000:9000 \ -e SONAR_JDBC_URL=jdbc:postgresql://db:5432/sonar \ -e SONAR_JDBC_USERNAME=sonar \ -e SONAR_JDBC_PASSWORD=sonar \ sonarqube:community
Using Docker Compose
cat > docker-compose.yml << 'EOF' version: "3" services: sonarqube: image: sonarqube:community depends_on: - db environment: SONAR_JDBC_URL: jdbc:postgresql://db:5432/sonar SONAR_JDBC_USERNAME: sonar SONAR_JDBC_PASSWORD: sonar ports: - "9000:9000" volumes: - sonarqube_data:/opt/sonarqube/data - sonarqube_extensions:/opt/sonarqube/extensions - sonarqube_logs:/opt/sonarqube/logs db: image: postgres:13 environment: POSTGRES_USER: sonar POSTGRES_PASSWORD: sonar POSTGRES_DB: sonar volumes: - postgresql:/var/lib/postgresql - postgresql_data:/var/lib/postgresql/data
volumes: sonarqube_data: sonarqube_extensions: sonarqube_logs: postgresql: postgresql_data: EOF
docker-compose up -d ```_
Manuelle Installation
```bash
Download SonarQube
wget https://binaries.sonarsource.com/Distribution/sonarqube/sonarqube-9.9.0.65466.zip unzip sonarqube-9.9.0.65466.zip cd sonarqube-9.9.0.65466
Configure database (PostgreSQL recommended)
Edit conf/sonar.properties
cat >> conf/sonar.properties << 'EOF' sonar.jdbc.username=sonar sonar.jdbc.password=sonar sonar.jdbc.url=jdbc:postgresql://localhost/sonar EOF
Start SonarQube
bin/linux-x86-64/sonar.sh start
Check status
bin/linux-x86-64/sonar.sh status ```_
SonarScanner Installation
```bash
Download SonarScanner
wget https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-4.8.0.2856-linux.zip unzip sonar-scanner-cli-4.8.0.2856-linux.zip sudo mv sonar-scanner-4.8.0.2856-linux /opt/sonar-scanner
Add to PATH
echo 'export PATH="/opt/sonar-scanner/bin:$PATH"' >> ~/.bashrc source ~/.bashrc
Verify installation
sonar-scanner --version ```_
Installation des Paketmanagers
```bash
Ubuntu/Debian
wget -qO - https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-4.8.0.2856-linux.zip
macOS with Homebrew
brew install sonar-scanner
Using npm
npm install -g sonarqube-scanner ```_
Grundkonfiguration
SonarQube Server Konfiguration
```properties
conf/sonar.properties
Database configuration
sonar.jdbc.username=sonar sonar.jdbc.password=sonar sonar.jdbc.url=jdbc:postgresql://localhost/sonar
Web server configuration
sonar.web.host=0.0.0.0 sonar.web.port=9000 sonar.web.context=/sonar
Elasticsearch configuration
sonar.search.javaOpts=-Xmx512m -Xms512m -XX:MaxDirectMemorySize=256m
Security configuration
sonar.security.realm=LDAP sonar.authenticator.downcase=true
Quality gate configuration
sonar.qualitygate.wait=true ```_
Projektkonfiguration (sonar-project.properties)
```properties
sonar-project.properties
Project identification
sonar.projectKey=my-project sonar.projectName=My Project sonar.projectVersion=1.0
Source code configuration
sonar.sources=src sonar.tests=tests sonar.sourceEncoding=UTF-8
Language-specific settings
sonar.java.source=11 sonar.java.target=11 sonar.java.binaries=target/classes sonar.java.libraries=target/dependency/*.jar
Exclusions
sonar.exclusions=/test/,/*.min.js,/vendor/ sonar.test.exclusions=/test/**
Coverage reports
sonar.coverage.jacoco.xmlReportPaths=target/site/jacoco/jacoco.xml sonar.javascript.lcov.reportPaths=coverage/lcov.info ```_
Basisnutzung
Laufender SonarScanner
```bash
Basic scan
sonar-scanner
Scan with custom properties
sonar-scanner \ -Dsonar.projectKey=my-project \ -Dsonar.sources=. \ -Dsonar.host.url=http://localhost:9000 \ -Dsonar.login=your-token
Scan specific directory
sonar-scanner -Dsonar.sources=src/main/java
Scan with exclusions
sonar-scanner \ -Dsonar.exclusions="/test/,/*.min.js" \ -Dsonar.test.exclusions="/test/**"
Debug mode
sonar-scanner -X ```_
Authentication
```bash
Generate authentication token
curl -u admin:admin -X POST "http://localhost:9000/api/user_tokens/generate?name=my-token"
Use token in scan
sonar-scanner -Dsonar.login=your-generated-token
Use username/password (not recommended)
sonar-scanner -Dsonar.login=admin -Dsonar.password=admin ```_
Qualitätstore
```bash
Check quality gate status
curl -u token: "http://localhost:9000/api/qualitygates/project_status?projectKey=my-project"
Set quality gate for project
curl -u token: -X POST "http://localhost:9000/api/qualitygates/select?projectKey=my-project&gateId;=1"
Create custom quality gate
curl -u token: -X POST "http://localhost:9000/api/qualitygates/create?name=Custom+Gate" ```_
Sprach-spezifische Konfiguration
Java Projekte
```properties
Maven integration
sonar.java.source=11
sonar.java.target=11
sonar.java.binaries=target/classes
sonar.java.libraries=target/dependency/.jar
sonar.java.test.binaries=target/test-classes
sonar.java.test.libraries=target/dependency/.jar
sonar.coverage.jacoco.xmlReportPaths=target/site/jacoco/jacoco.xml
_
xml
_
bash
Maven scan
mvn clean verify sonar:sonar \ -Dsonar.projectKey=my-project \ -Dsonar.host.url=http://localhost:9000 \ -Dsonar.login=your-token ```_
JavaScript/TypScript Projekte
```properties
JavaScript configuration
sonar.sources=src
sonar.tests=test
sonar.javascript.lcov.reportPaths=coverage/lcov.info
sonar.typescript.lcov.reportPaths=coverage/lcov.info
sonar.exclusions=node_modules/,dist/,build/**
_
json
// package.json script
\\{
"scripts": \\{
"sonar": "sonar-scanner"
\\}
\\}
```_
Python Projekte
```properties
Python configuration
sonar.sources=src sonar.tests=tests sonar.python.coverage.reportPaths=coverage.xml sonar.python.xunit.reportPath=test-reports/xunit.xml ```_
C# Projekte
```properties
C# configuration
sonar.cs.dotcover.reportsPaths=dotCover.html sonar.cs.nunit.reportsPaths=TestResult.xml sonar.cs.opencover.reportsPaths=opencover.xml ```_
CI/CD Integration
GitHub Aktionen
```yaml
.github/workflows/sonarqube.yml
name: SonarQube Analysis
on: push: branches: [ main, develop ] pull_request: branches: [ main ]
jobs: sonarqube: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 with: fetch-depth: 0
- name: Set up JDK 11
uses: actions/setup-java@v3
with:
java-version: '11'
distribution: 'temurin'
- name: Cache SonarQube packages
uses: actions/cache@v3
with:
path: ~/.sonar/cache
key: $\\\\{\\\\{ runner.os \\\\}\\\\}-sonar
restore-keys: $\\\\{\\\\{ runner.os \\\\}\\\\}-sonar
- name: Cache Maven packages
uses: actions/cache@v3
with:
path: ~/.m2
key: $\\\\{\\\\{ runner.os \\\\}\\\\}-m2-$\\\\{\\\\{ hashFiles('**/pom.xml') \\\\}\\\\}
restore-keys: $\\\\{\\\\{ runner.os \\\\}\\\\}-m2
- name: Build and analyze
env:
GITHUB_TOKEN: $\\\\{\\\\{ secrets.GITHUB_TOKEN \\\\}\\\\}
SONAR_TOKEN: $\\\\{\\\\{ secrets.SONAR_TOKEN \\\\}\\\\}
run: mvn clean verify org.sonarsource.scanner.maven:sonar-maven-plugin:sonar
```_
GitLab CI
```yaml
.gitlab-ci.yml
stages: - test - sonarqube
sonarqube-check: stage: sonarqube image: maven:3.6.3-jdk-11 variables: SONAR_USER_HOME: "$\\{CI_PROJECT_DIR\\}/.sonar" GIT_DEPTH: "0" cache: key: "$\\{CI_JOB_NAME\\}" paths: - .sonar/cache script: - mvn verify sonar:sonar allow_failure: true only: - merge_requests - master - develop ```_
Jenkins Pipeline
```groovy // Jenkinsfile pipeline \\{ agent any
tools \\\\{
maven 'Maven-3.6.3'
jdk 'JDK-11'
\\\\}
environment \\\\{
SONAR_TOKEN = credentials('sonar-token')
\\\\}
stages \\\\{
stage('Checkout') \\\\{
steps \\\\{
checkout scm
\\\\}
\\\\}
stage('Build') \\\\{
steps \\\\{
sh 'mvn clean compile'
\\\\}
\\\\}
stage('Test') \\\\{
steps \\\\{
sh 'mvn test'
\\\\}
post \\\\{
always \\\\{
junit 'target/surefire-reports/*.xml'
\\\\}
\\\\}
\\\\}
stage('SonarQube Analysis') \\\\{
steps \\\\{
withSonarQubeEnv('SonarQube') \\\\{
sh 'mvn sonar:sonar'
\\\\}
\\\\}
\\\\}
stage('Quality Gate') \\\\{
steps \\\\{
timeout(time: 1, unit: 'HOURS') \\\\{
waitForQualityGate abortPipeline: true
\\\\}
\\\\}
\\\\}
\\\\}
\\} ```_
Azure DevOs
```yaml
azure-pipelines.yml
trigger: - main
pool: vmImage: 'ubuntu-latest'
variables: MAVEN_CACHE_FOLDER: $(Pipeline.Workspace)/.m2/repository MAVEN_OPTS: '-Dmaven.repo.local=$(MAVEN_CACHE_FOLDER)'
steps: - task: Cache@2 inputs: | key: 'maven | "$(Agent.OS)" | **/pom.xml' | restoreKeys: | maven|"$(Agent.OS)" maven path: $(MAVEN_CACHE_FOLDER) displayName: Cache Maven local repo
-
task: SonarQubePrepare@4 inputs: SonarQube: 'SonarQube' scannerMode: 'Other'
-
task: Maven@3 inputs: mavenPomFile: 'pom.xml' goals: 'clean verify' options: '-Dmaven.repo.local=$(MAVEN_CACHE_FOLDER)' javaHomeOption: 'JDKVersion' jdkVersionOption: '1.11'
-
task: SonarQubeAnalyze@4
-
task: SonarQubePublish@4 inputs: pollingTimeoutSec: '300' ```_
Erweiterte Konfiguration
Kundenspezifische Regeln und Qualitätsprofile
```bash
Export quality profile
curl -u token: "http://localhost:9000/api/qualityprofiles/export?qualityProfile=MyProfile&language;=java" > my-profile.xml
Import quality profile
curl -u token: -X POST -F "backup=@my-profile.xml" "http://localhost:9000/api/qualityprofiles/restore"
Create custom rule
curl -u token: -X POST \ "http://localhost:9000/api/rules/create" \ -d "custom_key=my-custom-rule" \ -d "name=My Custom Rule" \ -d "markdown_description=This is my custom rule" \ -d "severity=MAJOR" \ -d "status=READY" \ -d "template_key=java:S124" ```_
Webhooks Konfiguration
```bash
Create webhook
curl -u token: -X POST \ "http://localhost:9000/api/webhooks/create" \ -d "name=MyWebhook" \ -d "url=https://my-server.com/webhook" \ -d "project=my-project"
Test webhook
curl -u token: -X POST \ "http://localhost:9000/api/webhooks/deliveries" \ -d "webhook=webhook-id" ```_
Messtechnik
```bash
Analyze main branch
sonar-scanner \ -Dsonar.projectKey=my-project \ -Dsonar.branch.name=main
Analyze feature branch
sonar-scanner \ -Dsonar.projectKey=my-project \ -Dsonar.branch.name=feature/new-feature \ -Dsonar.branch.target=main
Analyze pull request
sonar-scanner \ -Dsonar.projectKey=my-project \ -Dsonar.pullrequest.key=123 \ -Dsonar.pullrequest.branch=feature/new-feature \ -Dsonar.pullrequest.base=main ```_
Sicherheitsanalyse
Sicherheit Hotspots
```bash
Get security hotspots
curl -u token: "http://localhost:9000/api/hotspots/search?projectKey=my-project"
Change hotspot status
curl -u token: -X POST \ "http://localhost:9000/api/hotspots/change_status" \ -d "hotspot=hotspot-key" \ -d "status=REVIEWED" \ -d "resolution=SAFE"
Add comment to hotspot
curl -u token: -X POST \ "http://localhost:9000/api/hotspots/add_comment" \ -d "hotspot=hotspot-key" \ -d "comment=This has been reviewed and is safe" ```_
Sicherheitsregeln Konfiguration
```properties
Enable security rules
sonar.security.hotspots.enabled=true sonar.security.review.enabled=true
OWASP Top 10 categories
sonar.security.owasp-a1.enabled=true sonar.security.owasp-a2.enabled=true sonar.security.owasp-a3.enabled=true sonar.security.owasp-a4.enabled=true sonar.security.owasp-a5.enabled=true sonar.security.owasp-a6.enabled=true sonar.security.owasp-a7.enabled=true sonar.security.owasp-a8.enabled=true sonar.security.owasp-a9.enabled=true sonar.security.owasp-a10.enabled=true
SANS Top 25 categories
sonar.security.sans-top25.enabled=true ```_
Automatisierung und Schrift
Automatisierte Qualität Gate Check
```python
!/usr/bin/env python3
sonar_quality_gate.py
import requests import sys import time import argparse
class SonarQubeQualityGate: def init(self, server_url, token, project_key): self.server_url = server_url.rstrip('/') self.token = token self.project_key = project_key self.session = requests.Session() self.session.auth = (token, '')
def get_project_status(self):
"""Get project quality gate status"""
url = f"\\\\{self.server_url\\\\}/api/qualitygates/project_status"
params = \\\\{'projectKey': self.project_key\\\\}
try:
response = self.session.get(url, params=params)
response.raise_for_status()
return response.json()
except requests.RequestException as e:
print(f"Error getting project status: \\\\{e\\\\}")
return None
def wait_for_analysis(self, timeout=300, interval=10):
"""Wait for analysis to complete"""
start_time = time.time()
while time.time() - start_time < timeout:
status = self.get_project_status()
if status and 'projectStatus' in status:
project_status = status['projectStatus']
if project_status.get('status') != 'IN_PROGRESS':
return status
print(f"Analysis in progress... waiting \\\\{interval\\\\} seconds")
time.sleep(interval)
else:
print("Could not get project status")
time.sleep(interval)
print(f"Timeout waiting for analysis to complete (\\\\{timeout\\\\}s)")
return None
def check_quality_gate(self):
"""Check if quality gate passes"""
status = self.get_project_status()
if not status:
return False, "Could not get project status"
project_status = status.get('projectStatus', \\\\{\\\\})
gate_status = project_status.get('status')
if gate_status == 'OK':
return True, "Quality gate passed"
elif gate_status == 'ERROR':
conditions = project_status.get('conditions', [])
failed_conditions = [c for c in conditions if c.get('status') == 'ERROR']
error_msg = "Quality gate failed:\n"
for condition in failed_conditions:
metric = condition.get('metricKey', 'Unknown')
actual = condition.get('actualValue', 'N/A')
threshold = condition.get('errorThreshold', 'N/A')
error_msg += f" - \\\\{metric\\\\}: \\\\{actual\\\\} (threshold: \\\\{threshold\\\\})\n"
return False, error_msg
else:
return False, f"Unknown quality gate status: \\\\{gate_status\\\\}"
def get_metrics(self):
"""Get project metrics"""
url = f"\\\\{self.server_url\\\\}/api/measures/component"
params = \\\\{
'component': self.project_key,
'metricKeys': 'bugs,vulnerabilities,code_smells,coverage,duplicated_lines_density'
\\\\}
try:
response = self.session.get(url, params=params)
response.raise_for_status()
data = response.json()
metrics = \\\\{\\\\}
for measure in data.get('component', \\\\{\\\\}).get('measures', []):
metrics[measure['metric']] = measure.get('value', '0')
return metrics
except requests.RequestException as e:
print(f"Error getting metrics: \\\\{e\\\\}")
return \\\\{\\\\}
def print_summary(self):
"""Print analysis summary"""
metrics = self.get_metrics()
print("\n=== SonarQube Analysis Summary ===")
print(f"Project: \\\\{self.project_key\\\\}")
print(f"Bugs: \\\\{metrics.get('bugs', 'N/A')\\\\}")
print(f"Vulnerabilities: \\\\{metrics.get('vulnerabilities', 'N/A')\\\\}")
print(f"Code Smells: \\\\{metrics.get('code_smells', 'N/A')\\\\}")
print(f"Coverage: \\\\{metrics.get('coverage', 'N/A')\\\\}%")
print(f"Duplicated Lines: \\\\{metrics.get('duplicated_lines_density', 'N/A')\\\\}%")
def main(): parser = argparse.ArgumentParser(description='SonarQube Quality Gate Checker') parser.add_argument('--server', required=True, help='SonarQube server URL') parser.add_argument('--token', required=True, help='Authentication token') parser.add_argument('--project', required=True, help='Project key') parser.add_argument('--wait', action='store_true', help='Wait for analysis to complete') parser.add_argument('--timeout', type=int, default=300, help='Timeout in seconds')
args = parser.parse_args()
qg = SonarQubeQualityGate(args.server, args.token, args.project)
if args.wait:
print("Waiting for analysis to complete...")
status = qg.wait_for_analysis(timeout=args.timeout)
if not status:
print("Analysis did not complete within timeout")
sys.exit(1)
qg.print_summary()
passed, message = qg.check_quality_gate()
print(f"\n\\\\{message\\\\}")
sys.exit(0 if passed else 1)
if name == 'main': main() ```_
Bulk Project Management
```bash
!/bin/bash
bulk_sonar_scan.sh
Configuration
SONAR_SERVER="http://localhost:9000" SONAR_TOKEN="your-token" PROJECTS_DIR="/path/to/projects" REPORTS_DIR="/path/to/reports"
Function to scan project
scan_project() \\{ local project_path="$1" local project_name=$(basename "$project_path")
echo "Scanning $project_name..."
cd "$project_path"
# Create sonar-project.properties if it doesn't exist
if [ ! -f "sonar-project.properties" ]; then
cat > sonar-project.properties << EOF
sonar.projectKey=$project_name sonar.projectName=$project_name sonar.projectVersion=1.0 sonar.sources=. sonar.exclusions=/node_modules/,/target/,/build/,/.git/ EOF fi
# Run scan
sonar-scanner \
-Dsonar.host.url="$SONAR_SERVER" \
-Dsonar.login="$SONAR_TOKEN" \
-Dsonar.projectKey="$project_name"
# Check quality gate
python3 sonar_quality_gate.py \
--server "$SONAR_SERVER" \
--token "$SONAR_TOKEN" \
--project "$project_name" \
--wait
if [ $? -ne 0 ]; then
echo "$project_name" >> "$REPORTS_DIR/failed_quality_gates.txt"
fi
\\}
Create reports directory
mkdir -p "$REPORTS_DIR"
Scan all projects
find "$PROJECTS_DIR" -maxdepth 1 -type d|while read -r project_dir; do if [ "$project_dir" != "$PROJECTS_DIR" ]; then scan_project "$project_dir" fi done
echo "Bulk scanning completed. Check $REPORTS_DIR for results." ```_
Best Practices
Qualität Gate Konfiguration
json
\\\\{
"name": "Strict Security Gate",
"conditions": [
\\\\{
"metric": "new_vulnerabilities",
"op": "GT",
"error": "0"
\\\\},
\\\\{
"metric": "new_bugs",
"op": "GT",
"error": "0"
\\\\},
\\\\{
"metric": "new_security_hotspots_reviewed",
"op": "LT",
"error": "100"
\\\\},
\\\\{
"metric": "new_coverage",
"op": "LT",
"error": "80"
\\\\},
\\\\{
"metric": "new_duplicated_lines_density",
"op": "GT",
"error": "3"
\\\\}
]
\\\\}
_
Projektorganisation
```properties
Multi-module project configuration
sonar.projectKey=my-company:my-project sonar.projectName=My Project sonar.projectVersion=1.0
Module configuration
sonar.modules=module1,module2,module3
module1.sonar.projectName=Module 1 module1.sonar.sources=module1/src module1.sonar.tests=module1/test
module2.sonar.projectName=Module 2 module2.sonar.sources=module2/src module2.sonar.tests=module2/test
module3.sonar.projectName=Module 3 module3.sonar.sources=module3/src module3.sonar.tests=module3/test ```_
Leistungsoptimierung
```properties
Performance tuning
sonar.scanner.metadataFilePath=.scannerwork/report-task.txt sonar.working.directory=.scannerwork sonar.scm.disabled=false sonar.scm.provider=git
Memory settings
sonar.scanner.javaOpts=-Xmx2048m -XX:MaxPermSize=256m
Parallel processing
sonar.scanner.dumpToFile=.scannerwork/scanner-report.json ```_
Fehlerbehebung
Gemeinsame Themen
```bash
Issue: Out of memory errors
Solution: Increase memory allocation
export SONAR_SCANNER_OPTS="-Xmx2048m"
Issue: Analysis taking too long
Solution: Exclude unnecessary files
sonar-scanner -Dsonar.exclusions="/node_modules/,/target/,/build/"
Issue: Quality gate webhook not working
Solution: Check webhook configuration and network connectivity
curl -X POST https://your-webhook-url.com/webhook -d '\\{"test": "data"\\}'
Issue: Branch analysis not working
Solution: Ensure proper branch configuration
sonar-scanner -Dsonar.branch.name=feature-branch -Dsonar.branch.target=main ```_
Debug Mode
```bash
Enable debug logging
sonar-scanner -X
Check scanner logs
tail -f .scannerwork/scanner-report.log
Verify server connectivity
curl -u token: "http://localhost:9000/api/system/status" ```_
Ressourcen
- SonarQube Offizielle Dokumentation
- SonarQube GitHub Repository
- [SonarQube Community](_LINK_5___ -%20SonarQube%20Rules
- SonarQube Plugins
--
*Dieses Betrugsblatt bietet umfassende Anleitung für die Verwendung von SonarQube, um Codequalität und Sicherheit zu erhalten. Regelmäßige Überwachung und richtige Konfiguration sind für eine effektive DevSecOps-Integration unerlässlich. *