cambios para worker-remoto
This commit is contained in:
parent
98e0cd0e46
commit
be56de7dd4
19 changed files with 1544 additions and 216 deletions
448
bugs.md
Normal file
448
bugs.md
Normal file
|
|
@ -0,0 +1,448 @@
|
|||
# Análisis de Errores e Inconsistencias - RSS2
|
||||
|
||||
Fecha de análisis: 2026-04-01
|
||||
|
||||
---
|
||||
|
||||
## Resumen Ejecutivo
|
||||
|
||||
Se han identificado **13 problemas** clasificados en:
|
||||
- 3 Errores Críticos
|
||||
- 7 Inconsistencias
|
||||
- 3 Warnings de Arquitectura
|
||||
|
||||
---
|
||||
|
||||
## 1. Errores Críticos
|
||||
|
||||
### 1.1 Rate Limiting No Implementado
|
||||
|
||||
**Ubicación:** `backend/internal/middleware/auth.go:104-108`
|
||||
|
||||
**Descripción:**
|
||||
La función existe pero no hace nada:
|
||||
```go
|
||||
func RateLimitMiddleware(requestsPerMinute int) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Problema:**
|
||||
No implementa ningún tipo de limitación de rate. Vulnerable a ataques de fuerza bruta y DoS.
|
||||
|
||||
**Impacto:** Alto - Seguridad comprometida.
|
||||
|
||||
---
|
||||
|
||||
### 1.2 CORS Demasiado Permisivo
|
||||
|
||||
**Ubicación:** `backend/internal/middleware/auth.go:77-90`
|
||||
|
||||
**Descripción:**
|
||||
```go
|
||||
c.Writer.Header().Set("Access-Control-Allow-Origin", "*")
|
||||
```
|
||||
|
||||
**Problema:**
|
||||
Permite cualquier origen, lo cual es inseguro para APIs de producción. Permite ataques CSRF y expone datos a orígenes maliciosos.
|
||||
|
||||
**Impacto:** Alto - Seguridad comprometida.
|
||||
|
||||
---
|
||||
|
||||
### 1.3 Secret Key Por Defecto Hardcodeada
|
||||
|
||||
**Ubicación:** `backend/internal/config/config.go:32`
|
||||
|
||||
**Descripción:**
|
||||
```go
|
||||
SecretKey: getEnv("SECRET_KEY", "change-this-secret-key"),
|
||||
```
|
||||
|
||||
**Problema:**
|
||||
Si no se proporciona la variable de entorno, la aplicación usa una clave por defecto conocida. Cualquier despliegue sin configurar esta variable es vulnerable.
|
||||
|
||||
**Impacto:** Crítico - Compromiso total de autenticación.
|
||||
|
||||
---
|
||||
|
||||
## 2. Inconsistencias
|
||||
|
||||
### 2.1 Mapeo de Campos Inconsistente (Snake Case vs Camel Case)
|
||||
|
||||
**Descripción:**
|
||||
La aplicación usa convenciones de nomenclatura diferentes en distintas capas:
|
||||
|
||||
| Capa | Estructura | Ejemplo |
|
||||
|------|------------|---------|
|
||||
| Models | Snake case | `Title`, `Summary`, `ImageURL` |
|
||||
| Handlers | Pascal case | `Titulo`, `Resumen`, `ImagenURL` |
|
||||
| Frontend TS | camelCase | `titulo`, `resumen`, `imagen_url` |
|
||||
|
||||
**Archivos afectados:**
|
||||
- `backend/internal/models/models.go:7-19`
|
||||
- `backend/internal/handlers/news.go:14-28`
|
||||
- `frontend/src/services/api.ts:20-34`
|
||||
|
||||
**Problema:**
|
||||
Dificulta el mantenimiento y genera potenciales errores de serialización.
|
||||
|
||||
---
|
||||
|
||||
### 2.2 Idioma de Traducción Hardcodeado
|
||||
|
||||
**Descripción:**
|
||||
El idioma destino de traducción (`es`) está hardcodeado en múltiples lugares:
|
||||
|
||||
**news.go:67:**
|
||||
```go
|
||||
where += " AND t.status = 'done' AND t.titulo_trad IS NOT NULL"
|
||||
```
|
||||
|
||||
**news.go:96:**
|
||||
```go
|
||||
LEFT JOIN traducciones t ON t.noticia_id = n.id AND t.lang_to = 'es'
|
||||
```
|
||||
|
||||
**search.go:34-37:**
|
||||
```go
|
||||
if lang == "" {
|
||||
lang = "es"
|
||||
}
|
||||
```
|
||||
|
||||
**Problema:**
|
||||
No es configurable. Si se quiere traducir a otros idiomas, requiere cambios en múltiples archivos.
|
||||
|
||||
---
|
||||
|
||||
### 2.3 Columna `role` en Users Sin映射 en Modelo
|
||||
|
||||
**Descripción:**
|
||||
Se añade una columna `role` a la tabla users:
|
||||
|
||||
**cmd/server/main.go:41-48:**
|
||||
```go
|
||||
_, err = db.GetPool().Exec(ctx, `
|
||||
ALTER TABLE users ADD COLUMN IF NOT EXISTS role VARCHAR(20) DEFAULT 'user'
|
||||
`)
|
||||
```
|
||||
|
||||
**Pero el modelo User no tiene este campo:**
|
||||
|
||||
**models/models.go:86-94:**
|
||||
```go
|
||||
type User struct {
|
||||
ID int64 `json:"id"`
|
||||
Email string `json:"email"`
|
||||
Username string `json:"username"`
|
||||
PasswordHash string `json:"-"`
|
||||
IsAdmin bool `json:"is_admin"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
```
|
||||
|
||||
**Problema:**
|
||||
La columna `role` nunca se usa realmente. Hay dos campos (`role` y `is_admin`) que pueden causar confusión.
|
||||
|
||||
---
|
||||
|
||||
### 2.4 Feature No Implementada en Discovery
|
||||
|
||||
**Ubicación:** `backend/cmd/discovery/main.go:129-133`
|
||||
|
||||
**Descripción:**
|
||||
```go
|
||||
func findFeedLinksInHTML(baseURL string) ([]string, error) {
|
||||
// Simple feed link finder - returns empty for now
|
||||
// In production, use goquery to parse HTML and find RSS/Atom links
|
||||
return []string{}, nil
|
||||
}
|
||||
```
|
||||
|
||||
**Problema:**
|
||||
El worker de discovery no puede encontrar feeds RSS embebidos en páginas HTML. Solo detecta feeds directos.
|
||||
|
||||
**Impacto:** Medio - Reduce la efectividad del descubrimiento de feeds.
|
||||
|
||||
---
|
||||
|
||||
### 2.5 LoggerMiddleware No Funcional
|
||||
|
||||
**Ubicación:** `backend/internal/middleware/auth.go:93-101`
|
||||
|
||||
**Descripción:**
|
||||
```go
|
||||
func LoggerMiddleware() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
c.Next()
|
||||
|
||||
status := c.Writer.Status()
|
||||
if status >= 400 {
|
||||
// Log error responses - pero no hace nada!
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Problema:**
|
||||
El logging de errores está commented out. No se registra nada.
|
||||
|
||||
---
|
||||
|
||||
### 2.6 Columnas de BD Diferentes a Modelos
|
||||
|
||||
**Descripción:**
|
||||
El handler `search.go` referencia columnas que no existen en los modelos:
|
||||
|
||||
**search.go:91-92:**
|
||||
```go
|
||||
SELECT n.id, n.titulo, n.resumen, n.contenido, n.url, n.imagen,
|
||||
n.feed_id, n.lang, n.categoria_id, n.pais_id, n.created_at, n.updated_at,
|
||||
```
|
||||
|
||||
**Pero en models.go:7-19:**
|
||||
```go
|
||||
type News struct {
|
||||
ID int64 `json:"id"`
|
||||
Title string `json:"title"`
|
||||
Summary string `json:"summary"`
|
||||
Content string `json:"content"`
|
||||
URL string `json:"url"`
|
||||
ImageURL *string `json:"image_url"`
|
||||
PublishedAt *time.Time `json:"published_at"`
|
||||
Lang string `json:"lang"`
|
||||
FeedID int64 `json:"feed_id"`
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
**Problema:**
|
||||
- Modelo usa `Title`, BD usa `titulo`
|
||||
- Modelo usa `Summary`, BD usa `resumen`
|
||||
- Modelo usa `ImageURL`, BD usa `imagen`
|
||||
- Modelo usa `PublishedAt`, BD usa `fecha`
|
||||
|
||||
Esto causa errores de serialización potenciales.
|
||||
|
||||
---
|
||||
|
||||
### 2.7 Inicialización de Base de Datos Duplicada
|
||||
|
||||
**Descripción:**
|
||||
Existen dos formas de conectar a la base de datos:
|
||||
|
||||
1. `db.Connect()` en `backend/internal/db/postgres.go:13`
|
||||
2. `workers.Connect()` en `backend/internal/workers/db.go`
|
||||
|
||||
**Problema:**
|
||||
Códigos duplicados que mantienen conexiones separadas. Puede causar problemas de pool de conexiones.
|
||||
|
||||
---
|
||||
|
||||
## 3. Warnings de Arquitectura
|
||||
|
||||
### 3.1 Creación de Tablas en Runtime
|
||||
|
||||
**Ubicación:** `backend/cmd/server/main.go:20-77`
|
||||
|
||||
**Descripción:**
|
||||
En lugar de usar migraciones formales, el servidor crea tablas al iniciar:
|
||||
|
||||
```go
|
||||
func initDB() {
|
||||
_, err := db.GetPool().Exec(ctx, `
|
||||
CREATE TABLE IF NOT EXISTS entity_aliases (...)
|
||||
`)
|
||||
// más tablas...
|
||||
}
|
||||
```
|
||||
|
||||
**Problema:**
|
||||
- No hay control de versiones
|
||||
- No hay rollback
|
||||
- Difícil de mantener en producción
|
||||
|
||||
**Recomendación:** Usar golang-migrate o similar.
|
||||
|
||||
---
|
||||
|
||||
### 3.2 No Hay Tests Unitarios
|
||||
|
||||
**Descripción:**
|
||||
No se encontraron archivos `*_test.go` en el código backend.
|
||||
|
||||
**Problema:**
|
||||
Sin tests, cualquier cambio puede romper funcionalidad existente sin detección.
|
||||
|
||||
---
|
||||
|
||||
### 3.3 Pool de Conexiones Sin Validación Periódica
|
||||
|
||||
**Ubicación:** `backend/internal/db/postgres.go`
|
||||
|
||||
**Descripción:**
|
||||
El pool se crea pero no hay health check periódico.
|
||||
|
||||
**Problema:**
|
||||
Las conexiones zombie pueden acumularse sin detección.
|
||||
|
||||
---
|
||||
|
||||
## 4. Recomendaciones de Corrección
|
||||
|
||||
### Alta Prioridad
|
||||
|
||||
1. **Unificar JWT Secret:** Usar un único package para manejar el secret
|
||||
2. **Implementar Rate Limiting:** Usar una librería como `golang.org/x/time/rate`
|
||||
3. **Configurar CORS correctamente:** Usar variable de entorno para orígenes permitidos
|
||||
4. **Forzar Secret Key:** Hacer requerida la variable `SECRET_KEY`
|
||||
|
||||
### Media Prioridad
|
||||
|
||||
5. **Traducir idioma configurable:** Pasar idioma como parámetro o configuración
|
||||
6. **Usar migraciones:** Implementar golang-migrate
|
||||
7. **Añadir tests:** Crear tests unitarios para handlers críticos
|
||||
8. **Corregir mapeo de campos:** Estandarizar snake_case en toda la aplicación
|
||||
|
||||
### Baja Prioridad
|
||||
|
||||
9. **Implementar LoggerMiddleware:** Añadir logging real
|
||||
10. **Implementar findFeedLinksInHTML:** Usar goquery para parsing HTML
|
||||
11. **Consolidar DB:** Unificar inicialización de base de datos
|
||||
|
||||
---
|
||||
|
||||
## 5. Estadísticas
|
||||
|
||||
| Tipo | Cantidad |
|
||||
|------|----------|
|
||||
| Errores Críticos | 3 |
|
||||
| Inconsistencias | 7 |
|
||||
| Warnings | 3 |
|
||||
| **Total** | **13** |
|
||||
|
||||
---
|
||||
|
||||
## 6. Problemas Adicionales Detectados
|
||||
|
||||
### 6.1 Mapeo de Campos Inconsistente (Frontend)
|
||||
|
||||
**Descripción:** El frontend usa `snake_case` pero los modelos Go usan `PascalCase`.
|
||||
|
||||
**Archivos:**
|
||||
- `frontend/src/services/api.ts` - usa `titulo`, `resumen`
|
||||
- `backend/internal/models/models.go` - usa `Title`, `Summary`
|
||||
|
||||
---
|
||||
|
||||
### 6.2 Structs Duplicados para Mismo Recurso
|
||||
|
||||
**Descripción:** `handlers/news.go` define `NewsResponse` diferente a `models/models.go:News`.
|
||||
|
||||
---
|
||||
|
||||
### 6.3 Query Params Inconsistentes
|
||||
|
||||
**Descripción:** Algunos handlers usan `category_id` (inglés) y otros `categoria_id` (español).
|
||||
|
||||
---
|
||||
|
||||
### 6.4 Duplicación Config DB
|
||||
|
||||
**Descripción:** API usa `DATABASE_URL`, workers usan `DB_HOST`, `DB_PORT`, etc.
|
||||
|
||||
---
|
||||
|
||||
### 6.5 Sin Health Checks en Workers
|
||||
|
||||
**Descripción:** Workers no implementan endpoint `/health`.
|
||||
|
||||
---
|
||||
|
||||
### 6.6 Manejo de Errores Inconsistente
|
||||
|
||||
**Descripción:** Mezcla de `gin.H{"error": ...}` y `models.ErrorResponse`.
|
||||
|
||||
---
|
||||
|
||||
## 7. Errores y Problemas Críticos Detectados
|
||||
|
||||
### 7.1 ~~Errores Ignorados Silenciosamente~~ **(RESUELTO)**
|
||||
|
||||
**Descripción:** Múltiples lugares donde errores eran ignorados sin logging.
|
||||
|
||||
**Ejemplos corregidos:**
|
||||
- `admin.go:488-492` - Ahora verifica errores de `db.GetPool().Exec()`
|
||||
- `admin.go:522` - Verifica error al actualizar estado
|
||||
|
||||
**Impacto:** Fallos silenciosos que pasan desapercibidos.
|
||||
|
||||
---
|
||||
|
||||
### 7.2 ~~Rutas Hardcodeadas~~ **(RESUELTO)**
|
||||
|
||||
**Descripción:** Rutas de archivos hardcodeadas en el código.
|
||||
|
||||
**Correcciones:**
|
||||
- `admin.go:469,474,509` - Ahora usa `config.Load().DockerComposeDir`
|
||||
- `server/main.go:113` - Ahora usa `cfg.WikiImagesPath`
|
||||
- Añadidos nuevos campos en config: `DockerComposeDir`, `WikiImagesPath`
|
||||
|
||||
---
|
||||
|
||||
## 7.3 Secret Key Por Defecto
|
||||
|
||||
**Descripción:** `config.go:32` usa clave por defecto known.
|
||||
|
||||
```go
|
||||
SecretKey: getEnv("SECRET_KEY", "change-this-secret-key")
|
||||
```
|
||||
|
||||
**Impacto:** Medio - Si no se configura, usar clave insegura.
|
||||
|
||||
---
|
||||
|
||||
### 7.4 Rate Limiting No Implementado
|
||||
|
||||
**Descripción:** `middleware/auth.go:104-108` tiene función vacía.
|
||||
|
||||
**Impacto:** Alto - Vulnerable a ataques de fuerza bruta.
|
||||
|
||||
---
|
||||
|
||||
### 7.5 CORS Demasiado Permisivo
|
||||
|
||||
**Descripción:** `middleware/auth.go:79` permite cualquier origen.
|
||||
|
||||
**Impacto:** Alto - Expuesto a ataques CSRF.
|
||||
|
||||
---
|
||||
|
||||
## 8. Recomendaciones de Corrección (Actualizado)
|
||||
|
||||
### Alta Prioridad (CRÍTICO)
|
||||
|
||||
1. ~~Unificar JWT Secret~~ ✅
|
||||
2. Implementar Rate Limiting
|
||||
3. ~~**Configurar CORS correctamente:** Usar variable de entorno~~ ✅
|
||||
4. ~~**Corregir manejo de errores:** No ignorar silenciosamente~~ ✅
|
||||
5. ~~**Eliminar rutas hardcodeadas**~~ ✅
|
||||
|
||||
### Media Prioridad
|
||||
|
||||
7. Idioma traducciones configurable
|
||||
8. Usar migraciones
|
||||
9. Añadir tests
|
||||
10. Corregir mapeo de campos
|
||||
|
||||
### Baja Prioridad
|
||||
|
||||
11. Implementar LoggerMiddleware
|
||||
12. Implementar findFeedLinksInHTML
|
||||
13. Consolidar DB
|
||||
14. Estandarizar respuestas API
|
||||
15. Añadir health checks
|
||||
Loading…
Add table
Add a link
Reference in a new issue