Contexto
Auditoría Suprema sub-área 4 (monitoring/ITSM/alerting) identificó 36 hallazgos:
- 8 ALTA (críticos — ja cerrados en PRs anteriores)
- 13 MEDIA
- 15 BAJA
Sesión 112 cierra los BAJA/MEDIA en un lote unificado.
Decisiones Técnicas
B1: Validación de risk_level
Problema: Políticas SLA/escalation con risk_level basura (ej. “FOOBAR”) nunca matchean un insight realmente existente → silenciosamente inerte.
Decisión:
- Constante centralizada
RISK_LEVELS = {"HIGH", "MEDIUM", "LOW"}enitsm_schemas.py - Validadores Pydantic en
EscalationPolicyInyKnownIssueIn - Endpoint
update_sla_policy(risk_level)rechaza fuera de set → 400
B5: Honestidad en apply_runbook
Problema: El endpoint “aplica” runbook pero no lo ejecuta realmente. Docstring ambiguo; usage_count se incrementaba en re-asignaciones (inflaba ranking).
Decisión:
- Docstring aclara: asigna, no ejecuta
- Response añade campo
assigned: True(junto aappliedpara compat) usage_countsolo se incrementa si es la PRIMERA vez asignado a este insight (re-asignar es idempotente)
B6: Body de create_from_insight
Problema: create_from_insight ignoraba description/risk_level del body; usaba solo los del insight.
Decisión: Aplicar campos del body si vienen, respetando entrada del usuario.
B10: SLA Lifecycle con resolved_by
Problema: AlertEvent.resolved_at se poblaba pero sin traza de quién lo hizo.
Decisión:
- Nueva FK
AlertEvent.resolved_by→ User resolve_alertendpoint pueblaresolved_byconrequest.user(si autenticado)- Al resolver, también marca
acknowledgedsi no lo estaba (ciclo SLA consistente) - Migración
monitoring/0022
B15: Markdown a Prueba de Fences
Problema: Bloque de código con ``` en commands/output rompía el fence Markdown.
Decisión: Función _code_block() que calcula fence más larga que cualquier run de backticks en el contenido.
M5: Validación de Comandos en Runbooks
Problema: create/update_runbook guardaban comandos embebidos sin validar contra allowlist del vendor.
Decisión:
- Función
_validate_runbook_commands(steps, vendor)llama avalidate_commands(cmds, vendor) - Rechaza runbook con comando peligroso → 400
- Se aplica en
create_runbookyupdate_runbook
B7/B11: Paginación en List Endpoints
Problema: Endpoints sin limit → potencial DoS o N+1 masivo.
Decisión:
list_alerts,get_active_alerts:limit/offset, cap 1000list_runbooks,list_known_issues:limit/offset, cap 500
B12: N+1 en is_in_maintenance_window
Problema: Cargaba TODAS las ventanas activas, luego probaba M2M por cada una.
Decisión: Query única con Q(targets__isnull=True) | Q(targets=target).
B13: N+1 en check_escalations
Problema: Cada insight disparaba una query de políticas.
Decisión: Precarga TODAS las políticas de las orgs pendientes, groupware por (org_id, risk_level), acceso O(1).
Nota sobre B8/M4/M11
- B8 (N+1 de evaluación de alertas): La parte cara (N+1 de
save) ya se cerró en M10 (PR #70). El resto es inherente al diseño per-target del evaluador — refactor mayor deferido. - M4/M11 (tests de autorización): Cubiertos por suite
test_monitoring_sa4_sa5.py.
Impacto
- Correctness: Políticas malformadas ya no quedan silenciosamente inertes
- Security: Runbooks no pueden ejecutar comandos peligrosos
- Performance: -N+1 significativos en escalation y maintenance checks
- Observability:
resolved_bytraza decisiones de cierre de alerts; usage ranking de runbooks más honesto - Safety: Reportes Markdown robustos ante contenido con backticks
Test Coverage
4 tests nuevos en test_monitoring_sa4_sa5.py:
- B1: risk_level inválido → 400
- M5: runbook con comando peligroso → 400
- B10: resolve_alert puebla resolved_by + acknowledged
- B5: apply_runbook idempotente en usage_count
Véase también
- [[feature—monitoring—sa4-baja-cleanup]]
- [[concept—monitoring—risk-stratification]]
- [[concept—monitoring—escalation-workflow]]
- [[entity—monitoring—service—escalation-policy-checker]]
- [[entity—monitoring—service—sla-maintenance-window]]