CreaRack-SL

Cerrar Broken Access Control en el CRUD de racks y en /api/settings

Contexto

Ronda de revisión funcional del 23-08-2026 (tasks #241 y #251) encontró que ninguna escritura del CRUD nuclear de racks (racks/api/racks.py, 13 endpoints) comprobaba el rol del usuario — solo get_current_org(request) filtraba por organización. Un usuario readonly podía crear, editar, clonar y borrar racks; un operator podía ejecutar operaciones que sus propios docstrings marcaban “(Admin)”: crear/aplicar plantillas y borrado permanente de la papelera.

En paralelo, /api/settings tenía 3 escrituras sin portero: session-timeout (ajuste de TODA la organización), onboarding/complete y onboarding/reset — solo exigían estar logueado.

Precedente: el helper require_perm (ver [[entity—core—service—require-perm]]) ya se había aplicado sistemáticamente en blueprints (s105), network ([[decision—20260609—require-perm-unified-authorization]]), vistas de monitoring ([[decision—20260604—broken-access-control-vistas-observatory]]) y signage ([[decision—20260609—signage-broken-access-control]]). El CRUD nuclear de racks (distinto de blueprints/api/racks.py, que sí tenía el guard desde s105) quedó fuera de esas rondas.

Opciones consideradas

  1. Guard manual endpoint a endpoint, sin test de contrato: rápido, pero repite el mismo error de fondo — un endpoint nuevo futuro puede volver a quedar sin gate y nadie lo nota hasta que alguien lo explota.
  2. require_perm en cada escritura + test registry-driven que recorre las operaciones REGISTRADAS en el router (no una lista a mano) y falla si alguna no llama a require_perm. Un endpoint nuevo sin gate rompe el CI solo.

Decisión elegida

Opción 2. require_perm(request, "racks", "edit") en las 13 escrituras de racks/api/racks.py + el restore de la papelera; require_perm(request, "racks", "admin") en las 4 operaciones destructivas/plantilla (create_template, apply_template, permanent_delete_rack, empty_rack_trash). require_perm(request, "users", "admin") en las 3 escrituras de /api/settings, con el esquema de session-timeout acotado a 0-120 (la API deja de depender de que la UI valide). El editor (racks/views.py::rack_editor) pasa can_edit = has_permission(user, "racks", "edit") al contexto y templates/editor.html/base.html ocultan la botonera de escritura a quien no lo tiene — cosmética honesta, la barrera real sigue siendo la API.

De regalo (task #251 pieza 1): las dos alarmas internas de core/tasks.py (check_tenant_integrity, monitor_db_connections) morían con TypeError al saltar porque pasaban un campo extra_data que [[entity—core—model—systemlog]] no tiene — el detalle pasa ahora al campo details (TextField) con level/category correctos.

Consecuencias

Pros:

  • Cierra un agujero de control de acceso real que llevaba en PROD desde que existen esos endpoints — el aislamiento entre organizaciones nunca estuvo afectado (RLS intacto), pero dentro de su propia organización escribía quien no debía.
  • tests/api/test_racks_permissions.py::TestWriteOpsDeclareGate (registry-driven) hace que un endpoint de escritura futuro sin gate rompa el CI automáticamente, sin depender de una checklist manual.
  • Las alarmas de integridad cross-tenant y saturación de conexiones DB vuelven a quedar registradas en SystemLog — antes fallaban en silencio.

Contras / riesgo asumido:

  • Cualquier integración o script interno que asumiera que un operator/readonly podía escribir en racks/settings deja de funcionar tras el deploy (cambio de comportamiento visible, documentado en RELEASE_NOTES).
  • El mismo patrón (permiso puntual sin test de contrato) puede seguir faltando en módulos aún no cubiertos por esta ronda — este fix cubre racks (CRUD nuclear) y settings, no todo el proyecto.

Status

Accepted — mergeado y desplegado en v1.82.0 (commit 38c182bc, PR #418).

Véase también

  • [[entity—core—service—require-perm]]
  • [[decision—20260609—require-perm-unified-authorization]]
  • [[decision—20260609—signage-broken-access-control]]
  • [[decision—20260604—broken-access-control-vistas-observatory]]
  • [[entity—core—model—systemlog]]
  • [[crearack—conceptos—usuarios-y-permisos]]
  • [[crearack—settings—user-management]]