El problema silencioso del código generado con IA
Las herramientas de IA generan código a una velocidad impresionante. Copilot, Claude, ChatGPT… puedes tener una feature funcionando en minutos. Pero velocidad no es sinónimo de calidad.
El resultado habitual es un acumulado silencioso de deuda técnica: código duplicado, funciones demasiado complejas, variables sin usar, vulnerabilidades que nadie revisó y tests que nunca se escribieron. El código funciona, pasa a producción, y nadie vuelve a mirarlo.
SonarQube actúa como el revisor senior que no descansa: analiza tu proyecto de forma estática, detecta bugs, huele code smells y levanta alertas de seguridad, independientemente de si el código lo escribiste tú o lo generó un modelo de IA.
En este artículo vamos a integrarlo en un proyecto Laravel con Laravel Sail, sin salir del entorno Docker. Cuando terminemos, con un solo script podremos lanzar un análisis completo y ver el resultado en el panel web.
¿Qué detecta SonarQube exactamente?
Antes de ponernos con la instalación, vale la pena entender qué nos va a dar SonarQube:
Bugs — errores que pueden causar comportamiento incorrecto en producción.
Vulnerabilidades — inyecciones SQL, XSS, credenciales expuestas, etc.
Code smells — código que funciona pero que dificulta el mantenimiento.
Deuda técnica — tiempo estimado de refactorización acumulado.
Cobertura de tests — qué porcentaje del código está cubierto por pruebas.
Duplicaciones — bloques de código repetidos que deberían estar abstraídos.
La edición Community es gratuita y más que suficiente para proyectos individuales o de equipo pequeño.
Requisitos
Laravel con Laravel Sail configurado.
Docker corriendo en local.
1. Añadir SonarQube al compose.yaml
Abrimos el compose.yaml y añadimos dos servicios nuevos dentro de services:: el propio SonarQube y su base de datos PostgreSQL.
sonarqube:
image: "sonarqube:community"
ports:
- "${SONARQUBE_PORT:-9000}:9000"
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"
networks:
- sail
depends_on:
sonarqube-db:
condition: service_healthy
sonarqube-db:
image: "postgres:16-alpine"
environment:
POSTGRES_USER: sonar
POSTGRES_PASSWORD: sonar
POSTGRES_DB: sonar
volumes:
- "sonarqube-db:/var/lib/postgresql/data"
networks:
- sail
healthcheck:
test: ["CMD-SHELL", "pg_isready -U sonar"]
interval: 10s
retries: 5
timeout: 5sTambién añadimos los volúmenes nuevos en la sección volumes: del mismo archivo:
sonarqube-data:
driver: local
sonarqube-extensions:
driver: local
sonarqube-logs:
driver: local
sonarqube-db:
driver: localLevantamos los contenedores nuevos sin tocar los que ya están corriendo:
./vendor/bin/sail up -d sonarqube sonarqube-dbSonarQube tarda entre 30 y 60 segundos en arrancar. La forma más sencilla de saber si está listo es abrir http://localhost:9000 en el navegador y esperar a que cargue el panel de login.
2. Primer acceso y cambio de contraseña
Abrimos el navegador en http://localhost:9000. El panel de SonarQube nos pedirá las credenciales por defecto:
Usuario:
adminContraseña:
admin
Al hacer login por primera vez, SonarQube nos obliga a cambiar la contraseña. Introducimos la contraseña actual (admin) y la nueva dos veces. Recomendamos guardarla en un gestor de contraseñas.
3. Crear el proyecto y obtener el token
Una vez dentro del panel, hay que crear un proyecto local y generar el token de autenticación que usará el scanner.
En la pantalla de bienvenida, hacemos clic en "Create a local project".
Rellenamos el Project key y el Display name. El project key debe coincidir con el valor que pondremos en
sonar-project.properties.Seleccionamos "Use the global setting" para la rama principal y hacemos clic en Next.
En la pantalla de análisis, elegimos "Locally".
SonarQube nos genera un token. Lo copiamos —solo se muestra una vez—.
Pegamos el token en el .env del proyecto:
SONARQUBE_PORT=9000
SONAR_PROJECT_KEY=project-key
SONAR_TOKEN=sqp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxImportante: asegúrate de que el
.envestá en el.gitignore. Un token filtrado permite analizar o modificar cualquier proyecto en tu instancia de SonarQube.
4. Configurar sonar-project.properties
Este archivo le indica al scanner qué analizar, dónde están los tests y cómo conectar con el servidor. Lo creamos en la raíz del proyecto Laravel:
sonar.projectKey=project-key
sonar.projectName=project-name
# Código fuente y tests
sonar.sources=app
sonar.tests=tests
# Configuración PHP
sonar.language=php
sonar.sourceEncoding=UTF-8
# URL del servidor SonarQube dentro de la red Docker
sonar.host.url=http://sonarqube:9000La URL apunta a http://sonarqube:9000 —el nombre del servicio en la red Docker de Sail— porque el scanner se ejecutará dentro de esa misma red. Si lo ejecutases desde fuera del entorno Docker, la URL sería http://localhost:9000.
5. Crear el script sonar.sh
En lugar de recordar el comando completo cada vez, encapsulamos todo en un script bash en la raíz del proyecto:
#!/bin/bash
set -e
# Lee el token desde el .env sin necesidad de exportarlo al shell
SONAR_TOKEN=$(grep '^SONAR_TOKEN=' .env | cut -d '=' -f2)
if [ -z "$SONAR_TOKEN" ]; then
echo "Error: SONAR_TOKEN not found in .env"
exit 1
fi
docker run --rm \
--network project_sail \
-v "$(pwd)":/usr/src \
-w /usr/src \
sonarsource/sonar-scanner-cli \
-Dsonar.token="$SONAR_TOKEN"El parámetro --network project_sail conecta el contenedor del scanner a la misma red Docker que Sail, lo que le permite resolver el hostname sonarqube. El nombre de la red sigue el patrón {directorio-del-proyecto}_sail. Si no estás seguro del nombre exacto, puedes verificarlo con:
docker network lsDamos permisos de ejecución al script:
chmod +x sonar.sh6. Ejecutar el análisis
Con Sail corriendo y el token configurado, lanzamos el scanner:
./sonar.shEl scanner descargará la imagen sonarsource/sonar-scanner-cli la primera vez, analizará el código y enviará los resultados. Cuando finalice veremos algo como:
INFO: Analysis report uploaded in 318ms
INFO: ANALYSIS SUCCESSFUL, you can find the results at:
INFO: http://localhost:9000/dashboard?id=project-key7. Interpretar el informe en el panel
Abrimos http://localhost:9000 y navegamos a nuestro proyecto. El dashboard principal muestra el Quality Gate: un semáforo global que indica si el código cumple o no los estándares mínimos configurados.
Las secciones más relevantes son:
Reliability — bugs potenciales. La valoración va de A (ninguno) a E (críticos).
Security — vulnerabilidades explotables.
Maintainability — deuda técnica acumulada expresada en tiempo de refactorización.
Coverage — porcentaje del código cubierto por tests.
Duplications — porcentaje de código duplicado.
Haciendo clic en cada categoría podemos ver el detalle archivo por archivo, con la línea exacta del problema y una explicación de cómo solucionarlo.
Integrar SonarQube en el flujo de trabajo diario
El mayor valor no está en ejecutarlo una vez, sino en convertirlo en parte del proceso habitual:
Ejecutar
./sonar.shantes de abrir un Pull Request.Añadirlo como paso en el pipeline de CI/CD (GitHub Actions, GitLab CI, etc.).
Configurar el Quality Gate para bloquear merges si la calidad baja de un umbral mínimo.
Revisar el panel con el equipo en las reuniones de sprint para priorizar la deuda técnica acumulada.
Conclusión
En un contexto donde la IA puede generar cientos de líneas de código en segundos, tener una herramienta que audite la calidad de forma sistemática no es un lujo, es una necesidad. SonarQube no reemplaza la revisión humana, pero elimina el ruido: cuando el código llega a code review, ya ha pasado por un primer filtro objetivo.
Con la configuración que hemos visto —tres archivos y un script bash— el setup completo no lleva más de 15 minutos, y el retorno en visibilidad y calidad es inmediato desde el primer análisis.
Curso Laravel 12
Completo 2026
El único curso 100% actualizado que incluye Laravel 12, Livewire 3, Vue 3, React 19 e Inertia 2. Aprende con proyectos reales y las últimas funcionalidades.
star Incluido en cualquier suscripción