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

6.3 KiB

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).