skills/sonarqube-quality-gate-playbook/SKILL.md
Playbook iterativo para llevar proyectos Node y TypeScript (NestJS + React en monorepo) a cumplir Quality Gates de SonarQube sin romper build ni pipelines. Usar cuando se necesite subir cobertura priorizando New Code, eliminar issues nuevos (Bugs, Vulnerabilities, Code Smells), revisar Security Hotspots y controlar duplicacion y deuda tecnica.
npx skillsauth add agustinalbonico/ai-customizations sonarqube-quality-gate-playbookInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Aplicar este flujo en iteraciones pequenas y verificables. Priorizar impacto real y bajo riesgo.
Definir estos inputs antes del primer ciclo:
SONAR_HOST_URL (ejemplo: http://127.0.0.1:9000)SONAR_TOKEN con permisos de analisisSONAR_PROJECT_KEY y opcional SONAR_PROJECT_NAMESONAR_NEW_CODE_REFERENCE_BRANCH (default: main)apps/backend, apps/frontend, packages/*lcov.info por appsonar-project.properties) o parametros equivalentes en CISeguir este orden de trabajo:
TO_REVIEWPara cada issue o archivo, calcular prioridad de manera simple:
priorityScore = (isNewCode*100) + (isBugOrVuln*80) + (isHotspotToReview*70) + severityWeight + (criticalPath*20) + (coverageGap*10) - (estimatedEffort*5)
Donde severityWeight puede ser: blocker 40, critical 30, major 20, minor 10.
No aceptar tests que solo suben porcentaje sin validar comportamiento:
Usar este runbook cuando SonarQube muestre cobertura mucho menor a la local.
SF: con backslashes (\\) en lcov.info generadas en Windows.\\.packages/utils) tirando abajo el global.SF: del lcov.info de cada app/package.sonar-scanner si hay archivos de coverage no mapeados o ignorados.Comandos sugeridos:
Get-Content "apps\\backend\\coverage\\lcov.info" | Select-String "^SF:" | Select-Object -First 10
Get-Content "apps\\frontend\\coverage\\lcov.info" | Select-String "^SF:" | Select-Object -First 10
Si aparecen rutas como SF:src\\app.ts, normalizar antes del scan.
/) en todos los lcov.info antes de sonar-scanner.Ejemplo portable (scripts/fix-lcov-paths.js):
const fs = require('node:fs');
const reports = [
'apps/backend/coverage/lcov.info',
'apps/frontend/coverage/lcov.info',
'packages/utils/coverage/lcov.info'
];
for (const reportPath of reports) {
if (!fs.existsSync(reportPath)) continue;
const content = fs.readFileSync(reportPath, 'utf8');
const normalized = content.replace(/\\\\/g, '/');
fs.writeFileSync(reportPath, normalized);
}
Guardrail CI (fallar si quedan backslashes):
if grep -q 'SF:.*\\\\' apps/backend/coverage/lcov.info; then
echo "ERROR: Backslashes encontrados en lcov.info"
exit 1
fi
Comandos genericos:
bun run --cwd apps/backend test -- --coverage
bun run --cwd apps/frontend test -- --coverage
sonar-scanner `
-Dsonar.host.url=$env:SONAR_HOST_URL `
-Dsonar.token=$env:SONAR_TOKEN `
-Dsonar.projectKey=$env:SONAR_PROJECT_KEY `
-Dsonar.qualitygate.wait=true
curl -4 -s "$env:SONAR_HOST_URL/api/measures/component?component=$env:SONAR_PROJECT_KEY&metricKeys=coverage,new_coverage,bugs,new_bugs,vulnerabilities,new_vulnerabilities,code_smells,new_code_smells,duplicated_lines_density,new_duplicated_lines_density" -u "$env:SONAR_TOKEN:"
curl -4 -s "$env:SONAR_HOST_URL/api/issues/search?componentKeys=$env:SONAR_PROJECT_KEY&resolved=false&inNewCodePeriod=true&types=BUG,VULNERABILITY,CODE_SMELL&ps=500" -u "$env:SONAR_TOKEN:"
curl -4 -s "$env:SONAR_HOST_URL/api/hotspots/search?projectKey=$env:SONAR_PROJECT_KEY&status=TO_REVIEW&ps=500" -u "$env:SONAR_TOKEN:"
Crear o actualizar sonar-project.properties en raiz con rutas reales del monorepo.
lcov.infosonar.javascript.lcov.reportPaths con todas las rutasSF: usen / y no \\lcov.info + archivos modificados del PRgit diff --name-only origin/main...HEAD | Where-Object { $_ -match '\.(ts|tsx)$' }
*.spec.ts*.test.tsxshould <resultado> when <condicion>returns <error> when <input invalido>Aplicar fixes quirurgicos, sin cambios de estilo masivos.
Checklist por categoria:
catch vacio, propagar con contextoExclusiones aceptables (con justificativo):
**/index.ts sin logica**/generated/**)Exclusiones no aceptables:
Regla: cada exclusion debe registrar el motivo tecnico.
Declarar ciclo completado solo con evidencia:
PASSEDnew_coverage >= 80new_bugs = 0new_vulnerabilities = 0new_code_smells = 0new_security_hotspots_reviewed = 100%Evidencia minima a adjuntar:
sonar-scanner con sonar.qualitygate.wait=truesonar.projectKey=my-org_my-monorepo
sonar.projectName=my-monorepo
sonar.sourceEncoding=UTF-8
sonar.sources=apps/backend/src,apps/frontend/src,packages
sonar.tests=apps/backend,apps/frontend,packages
sonar.test.inclusions=**/*.spec.ts,**/*.test.ts,**/*.test.tsx,**/*.spec.tsx
sonar.javascript.lcov.reportPaths=apps/backend/coverage/lcov.info,apps/frontend/coverage/lcov.info
sonar.newCode.referenceBranch=main
sonar.exclusions=**/dist/**,**/build/**,**/node_modules/**,**/*.d.ts
sonar.coverage.exclusions=**/index.ts,**/*.dto.ts,**/generated/**,**/*.stories.tsx
import type { Config } from 'jest';
const config: Config = {
preset: 'ts-jest',
testEnvironment: 'node',
collectCoverage: true,
coverageDirectory: 'coverage',
coverageReporters: ['text', 'lcov', 'html'],
collectCoverageFrom: [
'src/**/*.{ts,tsx}',
'!src/**/*.dto.ts',
'!src/**/index.ts',
'!src/**/generated/**'
]
};
export default config;
import { defineConfig } from 'vitest/config';
export default defineConfig({
test: {
environment: 'jsdom',
coverage: {
provider: 'v8',
reporter: ['text', 'lcov', 'html'],
reportsDirectory: './coverage',
include: ['src/**/*.{ts,tsx}'],
exclude: ['src/**/*.stories.tsx', 'src/**/index.ts']
}
}
});
name: quality-gate
on:
pull_request:
push:
branches: [main]
jobs:
quality:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: oven-sh/setup-bun@v2
- run: bun install --frozen-lockfile
- name: Backend tests with coverage
run: bun run --cwd apps/backend test -- --coverage
- name: Frontend tests with coverage
run: bun run --cwd apps/frontend test -- --coverage
- name: Normalize lcov paths (Windows/Linux safe)
run: node scripts/fix-lcov-paths.js
- name: Validate lcov path format
run: |
if grep -q 'SF:.*\\\\' apps/backend/coverage/lcov.info; then
echo "ERROR: Backslashes encontrados en backend lcov.info"
exit 1
fi
- name: Build
run: bun run build
- name: SonarQube Scan
env:
SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
run: |
sonar-scanner \
-Dsonar.host.url=$SONAR_HOST_URL \
-Dsonar.token=$SONAR_TOKEN \
-Dsonar.qualitygate.wait=true
stages:
- test
- quality
variables:
GIT_DEPTH: "0"
test_and_build:
stage: test
image: oven/bun:1
script:
- bun install --frozen-lockfile
- bun run --cwd apps/backend test -- --coverage
- bun run --cwd apps/frontend test -- --coverage
- node scripts/fix-lcov-paths.js
- bun run build
artifacts:
when: always
paths:
- apps/backend/coverage/
- apps/frontend/coverage/
sonarqube:
stage: quality
image: sonarsource/sonar-scanner-cli:latest
dependencies:
- test_and_build
script:
- sonar-scanner -Dsonar.host.url=$SONAR_HOST_URL -Dsonar.token=$SONAR_TOKEN -Dsonar.qualitygate.wait=true
allow_failure: false
Usar este resumen rapido en ejecucion:
Comandos base:
bun run --cwd apps/backend test -- --coveragebun run --cwd apps/frontend test -- --coveragesonar-scanner -Dsonar.host.url=$SONAR_HOST_URL -Dsonar.token=$SONAR_TOKEN -Dsonar.qualitygate.wait=truelcov.info sin backslashes en lineas SF:$env:SONAR_HOST_URL="http://127.0.0.1:9000"
$env:SONAR_TOKEN="<token>"
$env:SONAR_PROJECT_KEY="<project-key>"
bun run --cwd apps/backend test -- --coverage
bun run --cwd apps/frontend test -- --coverage
bun run build
sonar-scanner `
-Dsonar.host.url=$env:SONAR_HOST_URL `
-Dsonar.token=$env:SONAR_TOKEN `
-Dsonar.projectKey=$env:SONAR_PROJECT_KEY `
-Dsonar.qualitygate.wait=true
curl -4 -s "$env:SONAR_HOST_URL/api/measures/component?component=$env:SONAR_PROJECT_KEY&metricKeys=new_coverage,new_bugs,new_vulnerabilities,new_code_smells,new_duplicated_lines_density" -u "$env:SONAR_TOKEN:"
main803%data-ai
Automatically syncs skill metadata to AGENTS.md Auto-invoke sections. Trigger: Adding new skills, updating skill metadata, or regenerating skill routing tables.
development
Onboarding automático de proyectos existentes. Escanea el stack tecnológico, detecta componentes (backend, frontend, etc.), busca skills con `npx skills find`, audita seguridad, pide aprobación, instala y rutea a AGENTS.md automáticamente. Trigger: "onboarding del proyecto", "setup del proyecto", "configurar skills", "instalar skills para este proyecto".
tools
Trigger: verificar spec, probar spec, /verificar-spec, e2e visual. Ejecuta specs con Playwright MCP y documenta errores en iteracion 1/errores/.
development
Transforma ideas vagas en definiciones estructuradas de features mediante conversación adaptativa. Usa 5.5 fases (contexto, alcance, funcional, casos borde, técnico, review) para convertir una idea en un PRD de negocio y un Plan técnico con arquitectura. Genera dos documentos: <slug>-prd.md y <slug>-plan.md. El caso de uso es "quiero un..." o "/shape mi idea".