Files
Milton Gonzalez e65111a7f4 feat: version 3.0.0 -- Correcciones de auditoria de seguridad, accesibilidad y redundancia
Permisos (superadmin, viewer, busqueda, tareas recurrentes), bootstrap atomico,
revocacion de JWT por version de sesion (028), control optimista de edicion (029),
logo sin SVG + CSP, ingesta endurecida, correos escapados, borradores, paginacion
de proyectos, accesibilidad de dialogos/controles e i18n.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 11:36:02 -05:00

114 lines
6.3 KiB
Markdown

# Seguridad y Calidad — project.linkedcorp.net
> Copia ajustada de la plantilla del grupo (`project-md-templates/SEGURIDAD-Y-CALIDAD.md`). Léela
> antes de escribir código de una nueva funcionalidad y úsala como checklist antes de mergear.
>
> **Diferencia con la plantilla original**: la plantilla asume multi-empresa (`empresaId` por
> tenant). Este proyecto es de **una sola empresa** (single-company), así que el "aislamiento" que
> aplica aquí no es entre empresas sino entre **usuarios y su alcance por rol**: qué proyectos/
> actividades puede ver o tocar cada rol (ver tabla de roles en `SPEC.md`).
>
> Regla de oro: **la seguridad primero; luego, cero duplicación; luego, facilidad de revisión y de
> extender.**
---
## 1. Seguridad (NO negociable)
### 1.1 Alcance por rol (equivalente al aislamiento multi-tenant)
- **NUNCA** confíes en un `userId`/`role` que venga en el **body/query**. El usuario y su rol salen
SIEMPRE del token (`req.currentUser`), nunca del body.
- Reglas de alcance por rol (ver `SPEC.md`):
- **Colaborador**: solo puede ver/actualizar actividades y subtareas donde es `responsible_user_id`,
y comentar en los proyectos donde es miembro.
- **Coordinador/Líder**: solo puede crear/editar proyectos donde es `owner_user_id` o miembro
(`project_members`), y las actividades de esos proyectos.
- **Jefe de TI** y **Administrador**: sin restricción de alcance.
- **Consultor**: solo lectura en todo, ningún endpoint de escritura le responde 2xx.
- Antes de `update`/`delete`/`get by id` de un recurso, verificar que el usuario tiene alcance sobre
ese recurso (por rol + pertenencia al proyecto) y responder **404** si no corresponde (no 403,
para no revelar existencia a quien no debería ni saber que existe).
- Los IDs relacionados que llegan en el body (`projectId`, `activityId`, `dependsOnActivityId`, etc.)
deben validarse: que existan y que el usuario tenga alcance sobre ellos antes de usarlos.
### 1.2 Autenticación y autorización
- Toda ruta no pública pasa por middleware de auth (`backend/src/middleware/auth.js`).
- **Revalida en CADA request** que la cuenta siga activa (`users.is_active`). Un JWT válido por firma
NO basta: desactivar un usuario debe cortarle el acceso al instante, no cuando expire el token.
- La autorización del **frontend es solo UX** (ocultar botones/menús); el backend re-verifica rol y
alcance en cada endpoint. El usuario en `localStorage` es manipulable.
### 1.3 Secretos
- Contraseñas: `bcrypt` (cost ≥ 12). Nunca en logs ni respuestas.
- `.env` fuera de git. El arranque del backend debe **abortar en producción** si `JWT_SECRET` o las
credenciales de BD son valores por defecto/vacíos.
- No exponer rutas absolutas del filesystem del servidor en respuestas de API.
### 1.4 Entrada y datos
- **SQL siempre parametrizado** (placeholders `?`). Nunca concatenar entrada del usuario. Las
cláusulas `IN (...)` dinámicas se arman con placeholders, no con el valor.
- Nombres de columna/orden dinámicos SOLO desde una **whitelist** del servidor, jamás desde el query
string tal cual.
- Uploads (`attachments`): validar tamaño y **MIME por whitelist**. El nombre/ruta del archivo lo
genera el servidor (evita path traversal); nunca usar el nombre que manda el cliente como ruta.
- Fechas: validar coherencia (`due_date >= start_date`, etc.) en el servicio, no solo en el frontend.
### 1.5 Errores, logs y límites
- Los **5xx** ocultan el detalle al cliente en producción.
- **Rate limiting** en `POST /api/auth/login`.
- Sirviendo la SPA: CSP (helmet) — `script-src 'self'` (sin inline), `style-src 'self' 'unsafe-inline'`,
`img-src 'self' data: blob:`, `object-src 'none'`.
- La SPA de producción recibe CSP desde `frontend/public/serve.json` (el servidor `serve` copia
ese archivo al build); el backend usa Helmet en `/api`. En Vite dev no se aplica el header del
servidor `serve`, para permitir el módulo de recarga de React. El logo de empresa solo admite
PNG/JPG/WEBP comprobados por firma y se entrega con `nosniff`.
### 1.6 Frontend / caché
- El JWT en `localStorage` es un trade-off aceptado; mantener CSP y sanitización.
- Si en el futuro se agrega caché offline, purgarla en logout y en `401`.
---
## 2. Cero duplicación (procesos, flujos y funciones)
- Un helper vive en **un solo lugar**. Antes de escribir una función, buscar si ya existe.
- Helpers compartidos en `backend/src/utils/` (fechas, cálculo de `progress_pct`, cálculo de estado
de vencimiento 🟢/🟡/🔴) y `frontend/src/services`/`lib` (formateadores, `fmtDate`, `roleLabel`).
- El patrón CRUD repetido (listar/buscar/crear/editar/borrar) se abstrae en un hook reutilizable en
el frontend (`useAsync`/`useCrud`); loading/try-catch/ContentDialog de error, en un solo lugar.
- Una sola capa de API en el frontend (`src/services/api.js` con `api.get/post/put/delete`).
---
## 3. Orden, revisión y facilidad de extender
- Arquitectura backend por módulo: **routes → controller → service → repository → db**. Un módulo
nuevo replica esa forma (ver `projects`/`activities` como plantilla).
- **Un archivo, una responsabilidad.** Si un `service` crece mucho o mezcla temas, partirlo.
- Sin código muerto.
- Convención única de respuestas: `{ success, data, error }` en todos los endpoints; listados con
`{ items, total }` dentro de `data`.
- El cálculo de `progress_pct` (actividad y proyecto) vive en **un solo lugar** (`activities/service.js`
y `projects/service.js`), nunca duplicado en el frontend como fuente de verdad — el frontend solo
muestra el valor que devuelve la API.
---
## 4. Checklist antes de mergear / desplegar
Seguridad
- [ ] ¿El usuario/rol sale del token, no del body?
- [ ] ¿`update/delete/get-by-id` verifican alcance por rol (404 si no corresponde)?
- [ ] ¿La ruta tiene el middleware de auth/rol correcto? ¿Se revalida `is_active`?
- [ ] ¿SQL parametrizado (incl. `IN`)? ¿MIME/tamaño validados en adjuntos?
- [ ] ¿Secretos fuera de respuestas/logs? ¿5xx sin datos internos?
Calidad
- [ ] ¿Reutilicé helpers existentes en vez de duplicar?
- [ ] ¿Borré el código muerto que este cambio deja atrás?
- [ ] ¿El archivo/módulo sigue el patrón y no se volvió inmanejable?
Verificación
- [ ] Build/backend arrancan sin errores; smoke test del flujo tocado en dev.
- [ ] Migraciones idempotentes; respaldo antes de aplicarlas en producción (cuando exista deploy).