From 7fba253eac530d1ee260d8197936d0dd13f54f0a Mon Sep 17 00:00:00 2001 From: Santiago Hernandez Date: Mon, 19 Oct 2026 09:03:39 -0500 Subject: [PATCH] [SCRUM-1265] Quality Gate de SonarQube self-hosted para el servicio de reglas Agrega quality-gate.yml en dos jobs: pruebas, cobertura JaCoCo y compilado en ubuntu-latest; scanner en el runner self-hosted de la VM de Calidad con espera del Quality Gate (proyectos mani-java y mani-java-pr). Los PRs desde forks fallan el check en vez de omitirlo. La configuracion de Sonar pasa del pom.xml (SonarCloud) a sonar-project.properties, y ci.yml deja de intentar el analisis de SonarCloud. --- .github/workflows/ci.yml | 19 +---- .github/workflows/quality-gate.yml | 129 +++++++++++++++++++++++++++++ pom.xml | 9 +- sonar-project.properties | 27 ++++++ 4 files changed, 160 insertions(+), 24 deletions(-) create mode 100644 .github/workflows/quality-gate.yml create mode 100644 sonar-project.properties diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3d1743d..f718545 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,10 +1,8 @@ name: CI # Pruebas JUnit 5 + cobertura JaCoCo (QA-06 / SCRUM-1123) con umbral bloqueante -# (jacoco:check en `mvn verify`, ver pom.xml) y análisis SonarCloud con espera del -# Quality Gate (US-03.1.1-M6.3 / SCRUM-1227). El paso de Sonar corre solo si el -# secret SONAR_TOKEN existe: así un PR no falla mientras DevOps crea el proyecto -# Trama-AS_MANI-Java en SonarCloud. +# (jacoco:check en `mvn verify`, ver pom.xml). El análisis de SonarQube y su +# Quality Gate corren en quality-gate.yml (QA4-02 / SCRUM-1265). on: push: @@ -18,14 +16,9 @@ jobs: test: name: Pruebas (Java 17) runs-on: ubuntu-latest - env: - SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} steps: - name: Checkout code uses: actions/checkout@v4 - with: - # Sonar necesita el historial para atribuir código nuevo en PRs. - fetch-depth: 0 - name: Set up JDK 17 uses: actions/setup-java@v4 @@ -46,11 +39,3 @@ jobs: target/site/jacoco/ target/surefire-reports/ if-no-files-found: warn - - - name: SonarCloud + Quality Gate - if: env.SONAR_TOKEN != '' - run: mvn -B org.sonarsource.scanner.maven:sonar-maven-plugin:4.0.0.4121:sonar -Dsonar.qualitygate.wait=true - - - name: Aviso si Sonar no está configurado - if: env.SONAR_TOKEN == '' - run: echo "::warning::SONAR_TOKEN no configurado; se omitió el análisis de SonarCloud y su Quality Gate." diff --git a/.github/workflows/quality-gate.yml b/.github/workflows/quality-gate.yml new file mode 100644 index 0000000..e4a1fd8 --- /dev/null +++ b/.github/workflows/quality-gate.yml @@ -0,0 +1,129 @@ +name: Quality Gate + +# QA4-02 (SCRUM-1265): análisis de SonarQube Community con Quality Gate +# bloqueante (ADR-0005, Políticas §14.1). +# +# El servidor SonarQube vive en la VM de Calidad (red privada 10.43.x.x), que los +# runners de GitHub no alcanzan. Por eso el trabajo se divide en dos jobs: +# 1. pruebas_cobertura: corre en ubuntu-latest. Aquí se ejecuta el código del +# repositorio (mvn verify con jacoco:check) y se generan el bytecode, las +# dependencias y el reporte jacoco.xml. +# 2. sonar_quality_gate: corre en el runner self-hosted de la VM de Calidad +# (label "calidad"). Solo descarga el artefacto y ejecuta el scanner; no +# ejecuta Maven ni código del repositorio en la VM. +# +# SonarQube Community no analiza ramas ni PRs, así que se usan dos proyectos: +# - mani-java: push a develop (estado oficial de la rama). +# - mani-java-pr: pull requests, para no pisar el estado de develop. +# +# Para que el gate BLOQUEE el merge, el ruleset de develop, release y main debe +# exigir los dos checks: "Pruebas y cobertura" y "Sonar Quality Gate". Si las +# pruebas fallan, el job de Sonar queda omitido y GitHub cuenta un job omitido +# como aprobado. +# +# Requisitos: secreto SONAR_TOKEN y variable SONAR_HOST_URL (URL del servidor en +# la VM de Calidad), definidos en el repositorio o en la organización. + +on: + pull_request: + branches: [develop, release, main] + push: + branches: [develop] + +permissions: + contents: read + +# En PR se cancela la corrida anterior; en push a develop cada commit conserva +# su análisis. +concurrency: + group: quality-gate-${{ github.ref }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + +jobs: + pruebas_cobertura: + name: Pruebas y cobertura + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Configurar JDK 17 + uses: actions/setup-java@v4 + with: + distribution: temurin + java-version: '17' + cache: maven + + - name: Pruebas con cobertura y umbral (JaCoCo) + run: mvn -B verify + + # El scanner necesita las dependencias para resolver tipos (sonar.java.libraries). + - name: Copiar dependencias de compilación + run: mvn -B dependency:copy-dependencies -DincludeScope=compile -DoutputDirectory=target/dependency + + # jacoco.xml referencia las clases por paquete y archivo, sin rutas + # absolutas, así que sirve tal cual en el workspace del runner self-hosted. + - name: Publicar compilado y cobertura + uses: actions/upload-artifact@v4 + with: + name: compilado_java + path: | + target/classes + target/test-classes + target/dependency + target/site/jacoco/jacoco.xml + if-no-files-found: error + retention-days: 3 + + sonar_quality_gate: + name: Sonar Quality Gate + needs: pruebas_cobertura + # Los PRs desde forks no llegan al runner de la VM: su código no es de + # confianza y no tienen acceso a los secretos. En vez de omitir el job (un + # job omitido cuenta como aprobado), el job corre en ubuntu-latest y falla. + runs-on: ${{ (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository) && 'ubuntu-latest' || fromJSON('["self-hosted","calidad"]') }} + steps: + - name: Bloquear PRs desde forks + if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository + run: | + echo "::error::Los PRs desde forks no pasan el Quality Gate. Abra el PR desde una rama de Trama-AS." + exit 1 + + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Descargar compilado y cobertura + uses: actions/download-artifact@v4 + with: + name: compilado_java + path: target + + # Si falta el secreto o la variable, el job falla. Un check omitido o en + # verde sin análisis daría una falsa señal de calidad. + - name: Verificar configuración de SonarQube + env: + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + SONAR_HOST_URL: ${{ vars.SONAR_HOST_URL }} + run: | + if [ -z "$SONAR_TOKEN" ]; then + echo "::error::SONAR_TOKEN no está configurado en los secretos del repositorio." + exit 1 + fi + if [ -z "$SONAR_HOST_URL" ]; then + echo "::error::SONAR_HOST_URL no está configurada en las variables del repositorio." + exit 1 + fi + + # v8.2.2 fijada por SHA del tag (ba9859e). + - name: Análisis de SonarQube y espera del Quality Gate + uses: sonarsource/sonarqube-scan-action@ba9859eae8dd6bd29e412f25ddbbef3d032000f4 + env: + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + SONAR_HOST_URL: ${{ vars.SONAR_HOST_URL }} + with: + args: > + -Dsonar.projectKey=${{ github.event_name == 'pull_request' && 'mani-java-pr' || 'mani-java' }} + -Dsonar.qualitygate.wait=true + -Dsonar.qualitygate.timeout=300 diff --git a/pom.xml b/pom.xml index 2934eb1..ac2636b 100644 --- a/pom.xml +++ b/pom.xml @@ -17,13 +17,8 @@ 17 - - trama-as - Trama-AS_MANI-Java - https://sonarcloud.io - ${project.build.directory}/site/jacoco/jacoco.xml - **/ManiRulesApplication.java + 0.85 0.80 diff --git a/sonar-project.properties b/sonar-project.properties new file mode 100644 index 0000000..c1c5e55 --- /dev/null +++ b/sonar-project.properties @@ -0,0 +1,27 @@ +# ===================================================================== +# Configuración de SonarQube para MANI-Java (Rules Service) +# Referencia: ADR-0005 (SAST en CI/CD con SonarQube), QA4-02 (SCRUM-1265) +# Servidor: SonarQube Community de la VM de Calidad (self-hosted, no SonarCloud) +# ===================================================================== + +# Identificación del proyecto. En pull requests el workflow quality-gate.yml +# sobrescribe la clave con mani-java-pr (Community no analiza ramas ni PRs). +sonar.projectKey=mani-java +sonar.projectName=MANI-Java + +sonar.sourceEncoding=UTF-8 +sonar.java.source=17 + +# Rutas de código fuente y pruebas +sonar.sources=src/main/java +sonar.tests=src/test/java + +# Bytecode y dependencias compilados por el job "Pruebas y cobertura" en +# ubuntu-latest y descargados como artefacto: el runner de la VM no ejecuta Maven. +sonar.java.binaries=target/classes +sonar.java.test.binaries=target/test-classes +sonar.java.libraries=target/dependency/*.jar + +# Reporte de cobertura generado por "mvn verify" (jacoco-maven-plugin) +sonar.coverage.jacoco.xmlReportPaths=target/site/jacoco/jacoco.xml +sonar.coverage.exclusions=**/ManiRulesApplication.java