Plataforma web para el análisis estático de un lote de proyectos Java.
Integra SonarQube y SourceMeter en una única interfaz, con exportación de métricas en CSV, XML y JSON.
Universidad Nacional del Nordeste — Proyecto Final de Carrera, 2026
Autora: Celeste María Luz Ojeda Rodríguez
NexSCAT está desplegado y accesible en:
No es necesario instalar nada para explorarlo. Las instrucciones de instalación local a continuación son para quienes deseen ejecutar el sistema en su propio entorno.
- Descripción
- Arquitectura
- Requisitos
- Instalación local
- Despliegue cloud
- Configuración
- Uso
- Comandos útiles
- Reiniciar análisis
- Diagnóstico de errores
NexSCAT automatiza el análisis estático de lotes de proyectos Java combinando dos herramientas complementarias:
- SonarQube — detecta vulnerabilidades, code smells y métricas de mantenibilidad y seguridad.
- SourceMeter — calcula métricas detalladas de complejidad, acoplamiento, cohesión y herencia.
Los análisis se ejecutan en paralelo mediante Celery, los resultados se almacenan en PostgreSQL y se visualizan en un dashboard web con navegación jerárquica por Proyecto → Componente → Clase.
┌─────────────┐
│ Navegador │
└──────┬──────┘
│ HTTPS
┌──────▼──────┐
│ Cloudflare │ DNS + SSL/TLS + DDoS [solo cloud]
└──────┬──────┘
│ HTTP (interno)
┌──────▼──────┐
│ Nginx │ proxy inverso + archivos estáticos
└──────┬──────┘
│
┌──────▼──────┐
│ Django │ lógica de negocio + vistas
└──────┬──────┘
┌───────────────┼───────────────┐
┌──────▼──────┐ ┌──────▼──────┐ ┌──────▼──────┐
│ Redis │ │ PostgreSQL │ │ SonarQube │
│ (broker) │ │ (BD) │ │ (análisis) │
└──────┬──────┘ └─────────────┘ └─────────────┘
│
┌──────▼──────┐
│Celery Worker│ ejecuta SonarQube + SourceMeter en paralelo
└─────────────┘
En entorno local: el Navegador conecta directo a Nginx por HTTP (sin Cloudflare).
Flujo de análisis:
- El usuario importa proyectos (ZIP o repositorio GitHub) desde la interfaz web
- Django encola una tarea Celery por herramienta (SonarQube + SourceMeter en paralelo)
- SonarQube analiza vía
sonar-scannery expone métricas por su API REST - SourceMeter genera archivos CSV con métricas a nivel Package, Class y Method
- El sistema procesa y persiste todo en PostgreSQL
- El dashboard muestra métricas en tres niveles con opción de exportación
⚠️ NexSCAT requiere Linux nativo o VM Linux.
SourceMeter necesita que sus binarios y el directorio de resultados estén en el mismo filesystem.
En Windows con Docker Desktop o WSL2 esto no es posible por la separación entre el overlay de Docker y los bind mounts del host, lo que produce el errorInvalid cross-device link.
Se recomienda Ubuntu 22.04 o 24.04.
| Herramienta | Versión mínima |
|---|---|
| Docker Engine | 24.0 |
| Docker Compose | 2.0 |
| Git | 2.33 |
| Git LFS | cualquiera |
⚠️ Usar Docker Engine, no Docker Desktop.
| Recurso | Mínimo |
|---|---|
| RAM | 8 GB |
| Disco | 20 GB libres |
| CPU | 2+ núcleos |
sudo apt-get update
sudo apt-get install -y ca-certificates curl gnupg
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | \
sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
# En Ubuntu 25.04: usar repositorio 'noble' (24.04) por compatibilidad
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
https://download.docker.com/linux/ubuntu noble stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
# Ejecutar Docker sin sudo
sudo usermod -aG docker $USER
newgrp dockersudo apt-get install git-lfs
git lfs installgit clone https://github.com/CelesteOj22/nexscat.git
cd nexscatGit LFS descargará automáticamente el binario de SourceMeter (~384 MB) durante el clonado.
cp .env.example .envEditá .env con tus valores. Mínimo requerido:
DB_PASSWORD=tu_password
SECRET_KEY=tu_secret_key
SONARQUBE_TOKEN= # se completa en el paso 6
SCAT_MODE=developmentPara generar el SECRET_KEY:
python3 -c "import secrets; print(secrets.token_urlsafe(50))"mkdir -p ~/nexscat/sm_results
mkdir -p ~/nexscat/proyectos
mkdir -p ~/nexscat/toolsdocker compose -f docker-compose.local.yml up -dLa primera vez puede tardar varios minutos mientras Docker descarga y construye las imágenes. Para verificar que todos los servicios estén activos:
docker compose -f docker-compose.local.yml ps- Accedé a http://localhost:9000
- Login inicial:
admin/admin→ cambiá la contraseña cuando lo pida - Ir a: My Account → Security → Generate Token
- Copiá el token y actualizá
.env:SONARQUBE_TOKEN=squ_xxxxxxxxxxxxxxxxxxxxxxxx
- Reiniciá los contenedores:
docker compose -f docker-compose.local.yml restart
⚠️ Este paso es obligatorio. Sin él, SourceMeter fallará conInvalid cross-device link.
SourceMeter necesita que sus binarios y el directorio de resultados estén en el mismo filesystem. Al copiarlo al host, /opt/tools/sourcemeter y /opt/sm_results quedan en el filesystem nativo de Ubuntu.
# Asegurarse de que el worker esté corriendo
docker compose -f docker-compose.local.yml up -d celery_worker
# Copiar SourceMeter al host
docker cp nexscat_celery_local:/opt/tools/sourcemeter ~/nexscat/tools/sourcemeter
# Reiniciar para aplicar el bind mount
docker compose -f docker-compose.local.yml restart celery_worker web| Servicio | URL |
|---|---|
| Aplicación NexSCAT | http://localhost:8000 |
| Panel SonarQube | http://localhost:9000 |
| Monitor Celery (Flower) | http://localhost:5555 |
NexSCAT incluye un perfil de composición específico para producción (docker-compose.cloud.yml) que agrega Nginx como proxy inverso. El stack fue desplegado en una instancia Hetzner CPX42 (Ubuntu 22.04 LTS) con el dominio nexscat.com gestionado a través de Cloudflare (DNS + SSL/TLS + protección DDoS).
- Instancia Linux con al menos 16 GB de RAM (la CPX42 de Hetzner cubre los requisitos con holgura)
- Acceso SSH a la instancia
- Docker Engine, Docker Compose y Git LFS instalados (mismos pasos que en la instalación local)
# 1. Clonar el repositorio en el servidor (con LFS)
git clone https://github.com/CelesteOj22/nexscat.git
cd nexscat
# 2. Configurar variables de producción en .env
# Incluir ALLOWED_HOSTS, CSRF_TRUSTED_ORIGINS, DEBUG=False, etc.
# 3. Levantar el stack de producción
docker compose -f docker-compose.cloud.yml up --build -dUna vez desplegado, la aplicación queda accesible en https://nexscat.com.
Los servicios internos (SonarQube, Flower, PostgreSQL) no están expuestos públicamente y pueden consultarse mediante túneles SSH si es necesario.
| Variable | Descripción | Valor por defecto |
|---|---|---|
DB_PASSWORD |
Contraseña de PostgreSQL | 1234 |
SECRET_KEY |
Clave secreta de Django | (requerido) |
SONARQUBE_TOKEN |
Token de autenticación SonarQube | (requerido) |
DEBUG |
Modo debug de Django | True |
SCAT_MODE |
Modo de análisis | development |
MAX_PARALLEL_ANALYSIS |
Análisis simultáneos máximos | 2 |
| Modo | Descripción | Timeout |
|---|---|---|
development |
Local con recursos moderados | 7200s (2h) |
production |
Cloud / recursos limitados | 7200s (2h) |
balanced |
Balance rendimiento/recursos | 7200s (2h) |
performance |
Máximo rendimiento local | 1800s (30min) |
auto |
Detección automática |
variable |
⚠️ Evitá el modoautosi tus proyectos tardan más de 20 minutos en analizarse. Puede reducir el timeout a 1200s.
Los proyectos Java deben ubicarse en la carpeta proyectos/:
# Copiar un proyecto manualmente
cp -r /ruta/al/proyecto ~/nexscat/proyectos/nombre-proyecto-1.0
# Desde carpeta compartida de VirtualBox
rsync -av --progress /media/sf_nombre_carpeta/ ~/nexscat/proyectos/
rsynces recomendable para copias grandes: si se interrumpe, retoma desde donde quedó sin recopiar archivos ya transferidos.
La estructura esperada es:
~/nexscat/proyectos/
├── proyecto-a-1.0/
│ ├── src/
│ ├── pom.xml / build.xml
│ └── ...
├── proyecto-b-2.3/
└── ...
Desde la interfaz web importás el proyecto con la ruta /app/proyectos/nombre-proyecto-1.0.
# Ver estado de los contenedores
docker compose -f docker-compose.local.yml ps
# Ver logs de un servicio
docker compose -f docker-compose.local.yml logs web --tail=100
docker compose -f docker-compose.local.yml logs celery_worker --tail=100
# Seguir logs en tiempo real
docker compose -f docker-compose.local.yml logs -f celery_worker
# Reiniciar un servicio específico
docker compose -f docker-compose.local.yml restart celery_worker
# Bajar todos los servicios
docker compose -f docker-compose.local.yml down
# Levantar todos los servicios
docker compose -f docker-compose.local.yml up -d
# Reconstruir imágenes (tras cambios en Dockerfile)
docker compose -f docker-compose.local.yml up -d --buildPara borrar todos los datos de análisis y empezar desde cero:
# 1. Borrar resultados de SourceMeter
rm -rf ~/nexscat/sm_results/*
# 2. Borrar datos de la base de datos
docker exec -it nexscat_web_local python manage.py shell -c "
from main.models import Project, Component, Class, ProjectMeasure, ComponentMeasure, ClassMeasure
ClassMeasure.objects.all().delete()
ComponentMeasure.objects.all().delete()
ProjectMeasure.objects.all().delete()
Class.objects.all().delete()
Component.objects.all().delete()
Project.objects.all().delete()
print('✅ Todo borrado')
"
# 3. Borrar proyectos de SonarQube
docker exec -it nexscat_web_local python manage.py shell -c "
import requests
from django.conf import settings
token = settings.SONARQUBE_TOKEN
url = settings.SONARQUBE_URL
projects = requests.get(f'{url}/api/projects/search', auth=(token, '')).json()
for p in projects.get('components', []):
requests.post(f'{url}/api/projects/delete', auth=(token, ''), params={'project': p['key']})
print(f'Borrado: {p[\"key\"]}')
"docker compose -f docker-compose.local.yml logs celery_worker --tail=200 | \
grep -E "✅|❌|⚠️|critical error|succeeded|failed"| Error | Causa | Solución |
|---|---|---|
Invalid cross-device link |
SourceMeter no copiado al host | Ejecutar el paso 8 |
FindBugsTask: critical error |
No hay archivos .class compilados |
Verificar que _runFB = 'false' en sourceMeter.py |
TimeLimitExceeded(1200) |
Modo auto con timeout bajo |
Cambiar a SCAT_MODE=development en .env |
No se encontró directorio de análisis |
Ruta de resultados incorrecta | Verificar que la ruta en _buscar_directorio_analisis incluye project_name dos veces |
# Error de SourceMeter
docker compose -f docker-compose.local.yml logs celery_worker --tail=200 | \
grep -A 10 "DirectoryBasedAnalysisTask"
# Timeout de tareas
docker compose -f docker-compose.local.yml logs celery_worker --tail=100 | \
grep -E "TimeLimitExceeded|time limit|TIMEOUT"
# Ver CSVs generados por SourceMeter
find ~/nexscat/sm_results -name "*.csv" | head -20