CreaRack-SL

Endpoint receive_agent_alert — Ingesta de alertas del Agent

Resumen

Endpoint privado que recibe alertas desde el Agent local. Los agentes (dev-observatory, dev-auto-provision, etc.) lo invocan para reportar estado de targets (dispositivos monitoreados, racks, etc.).

Endpoint: POST /api/agent/alert

Módulo: terminal.api.sentinel (función receive_agent_alert)

Autenticación: JWT de Agent (Bearer token). El token codifica agent_id, tenant_id, email.

Requisitos de seguridad (s104) — Tenant isolation fix

Problema histórico: El endpoint confiaba en el tenant_id del body JSON en vez del JWT firmado. Esto permitía a un Agent con token de tenant A escribir alertas sobre targets de tenant B (bypass de RLS).

Fix (s104, 2026-06-02):

  • Añadir validación explícita: if agent_data["tenant_id"] != payload.tenant_id: return 401, {"error": "Tenant ID mismatch"}.
  • Usar agent_data["tenant_id"] (del JWT) para filtrar el MonitoringTarget, no el del body.

Flujo

  1. Cliente (Agent) invoca POST con Bearer token + JSON body.
  2. Parsear JWT → extraer agent_data = {agent_id, tenant_id, email}.
  3. Parsear body → extraer AgentAlertSchema = {agent_id, tenant_id, target_id, alert_type, message, timestamp}.
  4. Validar agent_data["agent_id"] == payload.agent_id → 401 si falla.
  5. NUEVO s104: Validar agent_data["tenant_id"] == payload.tenant_id → 401 si falla.
  6. Buscar target: MonitoringTarget.objects.filter(id=payload.target_id, organization_id=agent_data["tenant_id"]) (usar JWT tenant, no body).
  7. Si existe, crear MonitoringAlert (nota: hay un bug preexistente aquí, ver abajo).
  8. Response 200 o error.

Campos del schema

class AgentAlertSchema(BaseModel):
    agent_id: str
    tenant_id: int  # Ahora se valida contra el JWT
    target_id: int
    alert_type: str  # "warning", "critical", "info", etc.
    message: str
    timestamp: str  # ISO 8601

Bug preexistente (fuera de alcance s104)

La creación de MonitoringAlert en el happy path pasa kwargs inexistentes (alert_type, message). El modelo no los acepta → error 500. El endpoint nunca ha creado una alerta correctamente. Anotado para backlog.

Tests

  • tests/api/test_sentinel.py::test_alert_rejects_body_tenant_spoofing — Tenant mismatch → 401, sin alerta creada.
  • tests/api/test_sentinel.py::test_alert_matching_tenant_passes_guard — Tenant match → pasa el guard (luego 404 por target no existe, que demuestra que no fue rechazado antes).

Véase también

  • [[entity—terminal—model—agent-instance]]
  • [[entity—monitoring—model—monitoring-alert]]
  • [[entity—monitoring—model—monitoring-target]]
  • [[entity—terminal—service—generate-agent-token]]
  • [[feature—security—s104-auditoria-suprema-fixes-core]]
  • [[concept—saas—multi-tenancy]]