Saltar al contenido principal
Algunas llamadas a herramienta son demasiado consecuentes para permitirlas a ciegas y demasiado útiles para prohibirlas de plano — una escritura a base de datos en producción, una transferencia bancaria, un *.delete sobre datos reales. Para esas quieres una persona en el ciclo: retén la llamada, deja que un humano mire, luego procede solo con un sí. Eso es exactamente lo que hace el veredicto pending_approval. Esta página cubre el flujo de aprobación de agente con humano en el ciclo de extremo a extremo: cómo sale a la luz una llamada retenida, cómo un revisor la resuelve desde la consola o un webhook, y cómo el agente reenvía la llamada aprobada. Para dónde se sitúa el veredicto en la gramática de reglas, ver Reglas del Firewall; para el modelo de política a su alrededor, ver la Visión general del Firewall.

1. Cómo se ve una llamada retenida

Cuando una regla resuelve a pending_approval, el motor encola un registro de aprobación y la llamada no llega a la herramienta. El relay devuelve HTTP 400 con error.code firewall_approval_pending; el id de aprobación sobre el que el agente hará polling se lleva en el error.message legible por humanos:
{
  "error": {
    "code": "firewall_approval_pending",
    "message": "tool \"db.write\" held for approval (…) — resolve approval 507f1f77bcf86cd799439011 and retry with header X-OrcaRouter-Firewall-Approval"
  }
}
El error.metadata estructurado (cuando está presente) lleva el detalle de la razón del veredicto — reason_code, factors, risk_score — no el id de aprobación. Parsea el id del mensaje, u obtenlo del helper del SDK de abajo. La retención es inmediata — no hay un long-poll en línea bloqueando tu solicitud. El agente obtiene el id de vuelta, la llamada se aparca del lado del servidor en el estado pending, y la resolución ocurre fuera de banda.
Una llamada retenida se registra como un evento del firewall con veredicto pending_approval, así que es filtrable en el registro de eventos justo junto a los eventos deny — siempre puedes ver qué se retuvo y, vía el registro de aprobación, qué se resolvió.

2. Un ejemplo concreto

Autora una regla que retiene cualquier escritura a una conexión de producción para un humano:
{
  "label": "hold prod db writes",
  "tool_name_glob": "db.write",
  "verdict": "pending_approval",
  "args_match_json": "{\"clauses\":[{\"path\":\"$.connection\",\"op\":\"eq\",\"value\":\"prod\"}]}"
}
Ahora el ciclo de vida:
1

El agente llama a la herramienta

El agente emite db.write contra prod. La regla coincide, el motor retiene la llamada, y el relay devuelve 400 firewall_approval_pending con un approval_id.
2

Un humano (o tu sistema) revisa

Un revisor resuelve la aprobación — en la consola o vía un callback de webhook firmado (ver §3).
3

El agente hace polling hasta que se resuelve

El agente hace polling del id de aprobación hasta que su estado ya no es pending (ver §4).
4

El agente reenvía con la cabecera de aprobación

En approved, el agente reemite la misma llamada exacta una vez, llevando una cabecera X-OrcaRouter-Firewall-Approval de un solo uso. El motor reclama la aprobación y deja pasar esa única llamada.

3. Resolver una aprobación

Hay dos formas de convertir una aprobación pending en approved o rejected. Ambas comparten una garantía de gana-la-primera-decisión — la primera resolución en aterrizar se aplica atómicamente, y cualquier resolución posterior (o un duplicado) es un no-op idempotente que devuelve 200.
La pestaña Approvals lista las retenciones pendientes de más antigua primero, cada una con el nombre de la herramienta y una línea “Held because…” que nombra la política y la cláusula de regla que se disparó. (Los argumentos de llamada en bruto no se almacenan en el registro de aprobación — solo el nombre de la herramienta, la procedencia y un hash de args — así que el revisor decide a partir de la herramienta más la cláusula coincidente.) Un revisor resuelve una con:
PATCH /api/workspace/firewall/approvals/:id
{ "decision": "approved", "reason": "verified change ticket #4821" }
decision debe ser approved o rejected. Esta ruta es UserAuth (la sesión de consola del revisor) y está gobernada a Developer+ — la identidad de tu revisor es la autorización, así que no hay ningún secreto compartido involucrado. Las resoluciones se escriben en el registro de auditoría del espacio de trabajo.
Para conectar las aprobaciones a un sistema externo (una aprobación de Slack, un flujo de tickets), configura un secreto de webhook de aprobación para el espacio de trabajo, luego haz POST de la decisión de vuelta:
POST /api/v1/firewall/approvals/:id/callback
{ "decision": "approved", "reason": "auto-approved by change-control bot" }
El callback se autentica con HMAC-SHA256: establece la cabecera X-Orca-Signature: sha256=<hex> al HMAC de <approval_id>\n<raw_body> con clave del secreto de webhook de aprobación de tu espacio de trabajo. El id es parte del material firmado, así que una firma capturada no se puede reproducir contra una aprobación diferente. Sin un secreto configurado, la resolución impulsada por callback se rechaza — resuelve vía el PATCH de la consola en su lugar.
Configurar una ruta de rechazo de webhook de aprobación es el valor por defecto seguro para ejecuciones desatendidas: si ningún humano resuelve una retención, la llamada simplemente sigue aparcada y el agente sigue haciendo polling. Una llamada retenida nunca se convierte silenciosamente en un allow.

4. Hacer polling, luego reenviar

El lado del agente es un bucle de polling seguido de un reenvío. Haz polling del estado de aprobación con un token con alcance de gateway de firewall:
GET /api/v1/firewall/approvals/:id
Esta ruta requiere un token con el alcance de gateway de firewall (la misma clave de gateway dedicada usada para /evaluate y el gateway MCP); una clave de relay normal obtiene 403. Devuelve el documento de aprobación — espera hasta que state sea approved o rejected en vez de pending. Un id de otro espacio de trabajo o desconocido devuelve 404, nunca revelando que existe a otro inquilino. Reenvía una vez que el estado es approved: reemite la misma llamada a herramienta, llevando el id de aprobación en una cabecera de un solo uso:
X-OrcaRouter-Firewall-Approval: 507f1f77bcf86cd799439011
El motor reclama atómicamente la aprobación — de un solo uso. El primer reenvío que la lleva se deja pasar esa única vez; una reproducción de la misma cabecera encuentra la aprobación ya consumida y se retiene de nuevo, no se permite. Una aprobación rejected nunca es reclamable, así que el agente debería tratar el rechazo como un deny terminal y elegir otra ruta.
El helper HITL del SDK MCP de OrcaRouter ejecuta este bucle de hacer polling-luego-reenviar por ti: cuando evaluate devuelve pending_approval, hace polling de GET /api/v1/firewall/approvals/:id y reenvía con la cabecera de aprobación al aprobar — tú solo autoras la regla y dotas de personal al revisor.

5. Estados y roles de un vistazo

EstadoSignificadoAcción del agente
pendingRetenida, esperando una decisiónSeguir haciendo polling
approvedEl revisor dijo síReenviar una vez con la cabecera
rejectedEl revisor dijo noTratar como un deny
AcciónRutaAuth · rol
Listar la colaGET /api/workspace/firewall/approvalsUserAuth · Developer+
ResolverPATCH /api/workspace/firewall/approvals/:idUserAuth · Developer+
Callback de webhookPOST /api/v1/firewall/approvals/:id/callbackFirmado con HMAC
Hacer polling del estadoGET /api/v1/firewall/approvals/:idToken de gateway

6. Dónde encajan las aprobaciones

Un veredicto pending_approval es uno de los veredictos del firewall — se compone con todo lo demás en una política. Dos interacciones que vale la pena conocer:
  • La cuarentena de skill escala a una retención. Si una llamada a herramienta retenida es propiedad de una skill en cuarentena, cualquier cosa por debajo de un deny se escala a pending_approval automáticamente — la cuarentena y las aprobaciones son la misma compuerta de revisión desde dos direcciones.
  • El modo shadow lo aplana. En modo shadow un veredicto pending_approval se degrada a audit y se registra como [shadow] would …, así que puedes medir con qué frecuencia una retención se dispararía antes de que empiece a gobernar tráfico real.
Este es el control correcto para llamadas a herramienta peligrosas y agencia excesiva — los casos donde un veredicto de “preguntar a un humano” supera tanto a allow como a deny.

Dónde ir a continuación

Veredictos

Los seis veredictos del firewall y el veredicto por defecto.

Claves de gateway

Acuña el token de gateway de firewall usado para hacer polling de aprobaciones.

Modo shadow

Mide una retención antes de que gobierne tráfico real.

Referencia de reglas

Autora la regla que produce un veredicto pending_approval.