Integration¶
Principe général¶
Le service d'analyse de qualité s'integre a trois niveaux : dans l'IDE du développeur (feedback instantane), dans le pipeline CI (quality gate automatique) et dans l'ecosysteme de la DSI (SSO, observabilité, alerting).
graph TD
IDE["IDE<br/>SonarLint + Semgrep"] --> SQ["SonarQube Server"]
CICD["Pipeline CI/CD<br/>Scanner + Quality Gate<br/>PR status"] --> SQ
DSI["Ecosysteme DSI<br/>Keycloak, Grafana<br/>Webhooks"] --> SQ Integration CI/CD — Gitea Actions¶
Workflow d'analyse SonarQube¶
# .gitea/workflows/quality.yml
name: Quality Analysis
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
quality:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0 # Historique complet pour l'analyse incrementale
- name: Setup Java
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'
- name: Build and test with coverage
run: |
./gradlew test jacocoTestReport
# ou pour Maven :
# mvn verify jacoco:report
- name: Semgrep SAST scan
run: |
pip install semgrep
semgrep scan \
--config auto \
--config .semgrep/rules/ \
--sarif \
--output semgrep-results.sarif
- name: SonarQube scan
uses: sonarsource/sonarqube-scan-action@v3
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}
with:
args: >
-Dsonar.projectKey=${{ gitea.repository }}
-Dsonar.sources=src/
-Dsonar.tests=test/
-Dsonar.coverage.jacoco.xmlReportPaths=build/reports/jacoco/test/jacocoTestReport.xml
-Dsonar.sarifReportPaths=semgrep-results.sarif
- name: Quality gate check
uses: sonarsource/sonarqube-quality-gate-action@v1
timeout-minutes: 5
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}
Configuration du projet SonarQube¶
# sonar-project.properties (a la racine du depot)
sonar.projectKey=mon-projet
sonar.projectName=Mon Projet
sonar.projectVersion=1.0
# Sources et tests
sonar.sources=src/main
sonar.tests=src/test
sonar.sourceEncoding=UTF-8
# Exclusions
sonar.exclusions=**/generated/**,**/vendor/**,**/node_modules/**
sonar.test.exclusions=**/test/**
# Couverture (adapter selon l'outil)
sonar.coverage.jacoco.xmlReportPaths=build/reports/jacoco/test/jacocoTestReport.xml
# sonar.python.coverage.reportPaths=coverage.xml
# sonar.javascript.lcov.reportPaths=coverage/lcov.info
# Import SARIF (resultats Semgrep)
sonar.sarifReportPaths=semgrep-results.sarif
Workflow pour projets Python¶
# .gitea/workflows/quality-python.yml
name: Quality Analysis (Python)
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
quality:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Install dependencies
run: |
pip install -r requirements.txt
pip install pytest pytest-cov semgrep
- name: Run tests with coverage
run: |
pytest --cov=src --cov-report=xml:coverage.xml
- name: Semgrep SAST scan
run: |
semgrep scan \
--config p/python \
--config p/security-audit \
--sarif \
--output semgrep-results.sarif
- name: SonarQube scan
uses: sonarsource/sonarqube-scan-action@v3
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}
with:
args: >
-Dsonar.projectKey=${{ gitea.repository }}
-Dsonar.sources=src/
-Dsonar.tests=tests/
-Dsonar.python.coverage.reportPaths=coverage.xml
-Dsonar.sarifReportPaths=semgrep-results.sarif
- name: Quality gate check
uses: sonarsource/sonarqube-quality-gate-action@v1
timeout-minutes: 5
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}
Semgrep en pre-commit¶
Configuration pre-commit¶
# .pre-commit-config.yaml
repos:
- repo: https://github.com/semgrep/semgrep
rev: v1.70.0
hooks:
- id: semgrep
args:
- --config
- p/security-audit
- --config
- .semgrep/rules/
- --error
stages: [pre-commit]
Pre-commit pour le feedback rapide
Semgrep en pre-commit détecte les problèmes de sécurité avant même le push. Le scan est rapide (< 30s sur la plupart des dépôts) et ne bloque pas le workflow du développeur.
Integration IDE — SonarLint¶
Configuration SonarLint pour VS Code¶
// .vscode/settings.json
{
"sonarlint.connectedMode.connections.sonarqube": [
{
"serverUrl": "https://sonar.example.com",
"token": "${env:SONAR_TOKEN}",
"connectionId": "organisation-sonarqube"
}
],
"sonarlint.connectedMode.project": {
"connectionId": "organisation-sonarqube",
"projectKey": "mon-projet"
}
}
Configuration SonarLint pour IntelliJ¶
- Préférences > Tools > SonarLint > Connections
- Ajouter une connexion SonarQube :
https://sonar.example.com - S'authentifier avec le token personnel
- Project Settings > SonarLint > Project Key :
mon-projet
Synchronisation des regles
SonarLint synchronise automatiquement les quality profiles du serveur SonarQube. Les développeurs voient les mêmes regles dans l'IDE et dans le pipeline CI, ce qui elimine les surprises au moment du push.
SSO Keycloak pour SonarQube¶
Configuration SAML dans Keycloak¶
# Creer le client SAML dans Keycloak
kcadm.sh create clients -r organization \
-s clientId=sonarqube \
-s enabled=true \
-s protocol=saml \
-s 'redirectUris=["https://sonar.example.com/oauth2/callback/saml"]' \
-s 'attributes.saml.assertion.signature=true' \
-s 'attributes.saml.server.signature=true' \
-s 'attributes.saml_name_id_format=username'
Configuration SonarQube (sonar.properties)¶
# /opt/sonarqube/conf/sonar.properties
# SAML Authentication
sonar.auth.saml.enabled=true
sonar.auth.saml.applicationId=sonarqube
sonar.auth.saml.providerName=Keycloak
sonar.auth.saml.providerId=https://auth.example.com/realms/organization
sonar.auth.saml.loginUrl=https://auth.example.com/realms/organization/protocol/saml
sonar.auth.saml.certificate.secured=MIICnTCCAYUCBgF...
sonar.auth.saml.user.login=login
sonar.auth.saml.user.name=name
sonar.auth.saml.user.email=email
sonar.auth.saml.group.name=groups
# Forcer l'authentification (pas d'acces anonyme)
sonar.forceAuthentication=true
Mapper les groupes Keycloak vers SonarQube
Configurer un mapper de type Group list dans le client SAML Keycloak pour transmettre les groupes de l'utilisateur. SonarQube peut ensuite mapper ces groupes sur des permissions par projet.
Variables d'environnement (Podman Compose)¶
# Ajouter dans le service sonarqube du podman-compose.yml
environment:
SONAR_AUTH_SAML_ENABLED: "true"
SONAR_AUTH_SAML_APPLICATIONID: "sonarqube"
SONAR_AUTH_SAML_PROVIDERNAME: "Keycloak"
SONAR_AUTH_SAML_PROVIDERID: "https://auth.example.com/realms/organization"
SONAR_AUTH_SAML_LOGINURL: "https://auth.example.com/realms/organization/protocol/saml"
SONAR_AUTH_SAML_USER_LOGIN: "login"
SONAR_AUTH_SAML_USER_NAME: "name"
SONAR_AUTH_SAML_USER_EMAIL: "email"
SONAR_AUTH_SAML_GROUP_NAME: "groups"
SONAR_FORCEAUTHENTICATION: "true"
Webhook vers Grafana / Alerting¶
Configurer le webhook SonarQube¶
# Creer un webhook global (tous les projets)
curl -u admin:TOKEN -X POST \
"http://localhost:9000/api/webhooks/create" \
-d "name=alerting-quality-gate" \
-d "url=https://alertmanager.example.com/api/v1/alerts" \
-d "secret=WEBHOOK_SECRET"
Payload du webhook¶
SonarQube envoie un payload JSON à chaque changement de statut du quality gate :
{
"serverUrl": "https://sonar.example.com",
"taskId": "AVh21JS2JepAEhwQ-b3u",
"status": "SUCCESS",
"analysedAt": "2026-04-16T14:32:15+0000",
"project": {
"key": "mon-projet",
"name": "Mon Projet",
"url": "https://sonar.example.com/dashboard?id=mon-projet"
},
"qualityGate": {
"name": "Organisation",
"status": "ERROR",
"conditions": [
{
"metric": "new_coverage",
"operator": "LESS_THAN",
"value": "65.2",
"status": "ERROR",
"errorThreshold": "80"
}
]
}
}
Alerte Prometheus via webhook receiver¶
# Configuration Alertmanager pour recevoir les webhooks SonarQube
# Utiliser un webhook-to-prometheus bridge ou un script custom
# qui traduit le payload SonarQube en alerte Prometheus
# Exemple de regle d'alerte Grafana
- alert: SonarQubeQualityGateFailed
expr: sonarqube_quality_gate_status{status="ERROR"} == 1
for: 0m
labels:
severity: warning
team: platform
annotations:
summary: "Quality gate en echec pour {{ $labels.project }}"
description: "Le projet {{ $labels.project }} ne passe plus le quality gate."
Auto-provisioning des projets depuis Gitea¶
Script de synchronisation¶
#!/bin/bash
# /home/sonarqube/scripts/sync-projects.sh
# Synchronise les depots Gitea avec les projets SonarQube
set -euo pipefail
GITEA_URL="https://git.example.com"
GITEA_TOKEN="${GITEA_TOKEN}"
SONAR_URL="http://localhost:9000"
SONAR_TOKEN="${SONAR_TOKEN}"
# Lister les depots Gitea
repos=$(curl -s -H "Authorization: token ${GITEA_TOKEN}" \
"${GITEA_URL}/api/v1/repos/search?limit=50" | jq -r '.[].full_name')
for repo in ${repos}; do
project_key=$(echo "${repo}" | tr '/' '-')
# Verifier si le projet existe deja dans SonarQube
exists=$(curl -s -u "${SONAR_TOKEN}:" \
"${SONAR_URL}/api/projects/search?projects=${project_key}" | \
jq -r '.components | length')
if [ "${exists}" -eq 0 ]; then
echo "Creation du projet SonarQube: ${project_key}"
curl -s -u "${SONAR_TOKEN}:" -X POST \
"${SONAR_URL}/api/projects/create" \
-d "name=${repo}" \
-d "project=${project_key}"
fi
done
echo "Synchronisation terminee: $(date)"
Cron de synchronisation¶
# /etc/cron.d/sonarqube-sync
# Synchroniser les projets toutes les heures
0 * * * * sonarqube /home/sonarqube/scripts/sync-projects.sh >> /var/log/sonarqube-sync.log 2>&1
Provisioning on-demand
Pour les organisations avec peu de dépôts, le provisioning automatique peut etre remplace par la creation manuelle des projets. L'auto-provisioning est utile à partir de 20+ dépôts.
Metriques Prometheus¶
Exporter les metriques SonarQube¶
SonarQube n'expose pas de metriques Prometheus nativement. Utiliser un exporter tiers :
# Ajouter au podman-compose.yml
sonarqube-exporter:
image: docker.io/ekzhang/sonarqube-exporter:latest
container_name: sonarqube-exporter
environment:
SONAR_URL: "http://sonarqube:9000"
SONAR_TOKEN: "${SONAR_TOKEN}"
ports:
- "9394:9394"
networks:
- sonarqube-net
depends_on:
- sonarqube
Configuration Prometheus¶
# prometheus.yml
scrape_configs:
- job_name: 'sonarqube'
static_configs:
- targets: ['sonarqube-exporter:9394']
scrape_interval: 5m
Dashboard Grafana¶
Metriques utiles a superviser :
| Metrique | Description |
|---|---|
sonarqube_projects_total | Nombre total de projets |
sonarqube_quality_gate_status | Statut du quality gate par projet |
sonarqube_coverage | Couverture de code par projet |
sonarqube_bugs | Nombre de bugs par projet |
sonarqube_vulnerabilities | Nombre de vulnerabilites par projet |
sonarqube_code_smells | Nombre de code smells par projet |
sonarqube_technical_debt_minutes | Dette technique en minutes par projet |