메인 콘텐츠로 건너뛰기
일부 툴 호출은 맹목적으로 허용하기에는 너무 중대하고 통째로 금지하기에는 너무 유용합니다 — 프로덕션 데이터베이스 쓰기, 송금, 실제 데이터에 대한 *.delete. 그런 것에는 사람을 루프에 두고 싶습니다: 호출을 보류하고, 사람이 보게 하고, 예가 나올 때만 진행. 그것이 정확히 pending_approval 판정이 하는 일입니다. 이 페이지는 human-in-the-loop 에이전트 승인 흐름을 처음부터 끝까지 다룹니다: 보류된 호출이 어떻게 표출되는지, 검토자가 콘솔이나 웹훅에서 어떻게 그것을 해결하는지, 그리고 에이전트가 승인된 호출을 어떻게 재제출하는지. 판정이 규칙 문법 어디에 위치하는지는 Firewall Rules를; 그 주변의 정책 모델은 Firewall 개요를 참조하세요.

1. 보류된 호출은 어떻게 보이는가

규칙이 pending_approval로 해석되면, 엔진은 승인 레코드를 큐에 넣고 호출은 툴에 도달하지 않습니다. 릴레이는 error.code firewall_approval_pending과 함께 HTTP 400을 반환합니다; 에이전트가 폴링할 승인 id는 사람이 읽을 수 있는 error.message에 담깁니다:
{
  "error": {
    "code": "firewall_approval_pending",
    "message": "tool \"db.write\" held for approval (…) — resolve approval 507f1f77bcf86cd799439011 and retry with header X-OrcaRouter-Firewall-Approval"
  }
}
구조화된 error.metadata(있을 때)는 승인 id가 아니라 판정의 이유 세부 — reason_code, factors, risk_score — 를 담습니다. 메시지에서 id를 파싱하거나, 아래의 SDK 헬퍼에서 가져오세요. 보류는 즉각적입니다 — 요청을 차단하는 인라인 long-poll이 없습니다. 에이전트는 id를 돌려받고, 호출은 서버 측에서 pending 상태로 주차되며, 해결은 대역 외에서 일어납니다.
보류된 호출은 판정 pending_approval을 가진 firewall 이벤트로 기록되므로, 이벤트 로그에서 deny 이벤트 바로 옆에 필터링 가능합니다 — 무엇이 보류되었는지, 그리고 승인 레코드를 통해 무엇이 해결되었는지 항상 볼 수 있습니다.

2. 하나의 구체적인 예

프로덕션 연결에 대한 모든 쓰기를 사람을 위해 보류하는 규칙을 작성하세요:
{
  "label": "hold prod db writes",
  "tool_name_glob": "db.write",
  "verdict": "pending_approval",
  "args_match_json": "{\"clauses\":[{\"path\":\"$.connection\",\"op\":\"eq\",\"value\":\"prod\"}]}"
}
이제 수명 주기:
1

에이전트가 툴 호출

에이전트가 prod에 대해 db.write을 발행합니다. 규칙이 매치하고, 엔진이 호출을 보류하고, 릴레이가 approval_id와 함께 400 firewall_approval_pending을 반환합니다.
2

사람(또는 시스템)이 검토

검토자가 승인을 해결합니다 — 콘솔에서 또는 서명된 웹훅 콜백을 통해 (§3 참조).
3

에이전트가 해결될 때까지 폴링

에이전트는 상태가 더 이상 pending이 아닐 때까지 승인 id를 폴링합니다(§4 참조).
4

에이전트가 승인 헤더와 함께 재제출

approved에서, 에이전트는 일회용 X-OrcaRouter-Firewall-Approval 헤더를 담아 정확히 같은 호출을 한 번 재발행합니다. 엔진이 승인을 청구하고 그 한 호출을 통과시킵니다.

3. 승인 해결하기

pending 승인을 approved 또는 rejected로 전환하는 방법은 두 가지입니다. 둘 다 첫 결정 승리 보장을 공유합니다 — 가장 먼저 떨어지는 해결이 원자적으로 적용되고, 이후의 어떤 해결(또는 중복)도 200을 반환하는 멱등적 no-op입니다.
Approvals 탭은 보류를 오래된 것 먼저 나열하며, 각각은 툴 이름과 발동한 정책 및 규칙 절을 명명하는 “Held because…” 라인을 가집니다. (원시 호출 인자는 승인 레코드에 저장되지 않습니다 — 툴 이름, 출처, 그리고 args 해시만 — 그래서 검토자는 툴과 매치된 절로 결정합니다.) 검토자는 다음으로 하나를 해결합니다:
PATCH /api/workspace/firewall/approvals/:id
{ "decision": "approved", "reason": "verified change ticket #4821" }
decisionapproved 또는 rejected이어야 합니다. 이 라우트는 UserAuth(검토자의 콘솔 세션)이며 **Developer+**로 게이트됩니다 — 검토자의 신원이 바로 인가이므로, 공유 시크릿이 관여하지 않습니다. 해결은 워크스페이스 감사 로그에 쓰입니다.
승인을 외부 시스템(Slack 승인, 티케팅 워크플로)에 배선하려면, 워크스페이스에 승인 웹훅 시크릿을 구성한 다음, 결정을 다시 POST하세요:
POST /api/v1/firewall/approvals/:id/callback
{ "decision": "approved", "reason": "auto-approved by change-control bot" }
콜백은 HMAC-SHA256으로 인증됩니다: X-Orca-Signature: sha256=<hex> 헤더를 워크스페이스의 승인 웹훅 시크릿으로 키가 지정된 <approval_id>\n<raw_body>의 HMAC으로 설정하세요. id는 서명된 자료의 일부이므로, 캡처된 서명이 다른 승인에 대해 재생될 수 없습니다. 구성된 시크릿이 없으면, 콜백 기반 해결이 거부됩니다 — 대신 콘솔 PATCH로 해결하세요.
승인 웹훅 거부 경로를 구성하는 것이 무인 실행을 위한 안전한 기본값입니다: 어떤 사람도 보류를 해결하지 않으면, 호출은 그저 주차된 채로 있고 에이전트는 계속 폴링합니다. 보류된 호출은 결코 조용히 allow가 되지 않습니다.

4. 폴링한 다음, 재제출

에이전트 측은 폴 루프에 이어 하나의 재제출입니다. firewall-gateway-scoped 토큰으로 승인 상태를 폴링하세요:
GET /api/v1/firewall/approvals/:id
이 라우트는 firewall-gateway 범위를 가진 토큰을 요구합니다(/evaluate와 MCP 게이트웨이에 사용되는 동일한 전용 게이트웨이 키); 일반 릴레이 키는 403을 받습니다. 승인 문서를 반환합니다 — statepending이 아니라 approvedrejected일 때까지 기다리세요. 교차 워크스페이스 또는 알 수 없는 id는 404를 반환하며, 다른 테넌트에게 그것이 존재함을 결코 드러내지 않습니다. 상태가 approved이면 한 번 재제출하세요: 같은 툴 호출을, 일회용 헤더에 승인 id를 담아 재발행하세요:
X-OrcaRouter-Firewall-Approval: 507f1f77bcf86cd799439011
엔진은 승인을 원자적으로 청구합니다 — 일회용. 그것을 담은 첫 재제출은 그 한 번 통과됩니다; 같은 헤더의 재생은 승인이 이미 소비된 것을 발견하고 허용되는 것이 아니라 다시 보류됩니다. rejected 승인은 결코 청구할 수 없으므로, 에이전트는 거부를 종착 deny로 다루고 다른 경로를 골라야 합니다.
OrcaRouter MCP SDK의 HITL 헬퍼는 이 폴-그다음-재제출 루프를 대신 실행합니다: evaluatepending_approval을 반환하면, GET /api/v1/firewall/approvals/:id를 폴링하고 승인 시 승인 헤더와 함께 재제출합니다 — 규칙을 작성하고 검토자를 배치하기만 하면 됩니다.

5. 상태와 역할 한눈에 보기

State의미에이전트 액션
pending보류됨, 결정 대기계속 폴링
approved검토자가 예라고 함헤더와 함께 한 번 재제출
rejected검토자가 아니오라고 함deny로 다룸
액션라우트Auth · 역할
큐 목록GET /api/workspace/firewall/approvalsUserAuth · Developer+
해결PATCH /api/workspace/firewall/approvals/:idUserAuth · Developer+
웹훅 콜백POST /api/v1/firewall/approvals/:id/callbackHMAC 서명
상태 폴링GET /api/v1/firewall/approvals/:id게이트웨이 토큰

6. 승인이 어디에 들어맞는가

pending_approval 판정은 firewall 판정 중 하나입니다 — 정책의 다른 모든 것과 조합됩니다. 알아둘 만한 두 상호작용:
  • Skill 격리가 보류로 격상됩니다. 보류된 툴 호출이 격리된 skill에 의해 소유되면, deny에 미치지 않는 모든 것이 자동으로 pending_approval로 격상됩니다 — 격리와 승인은 두 방향에서 같은 검토 게이트입니다.
  • Shadow mode가 그것을 평탄화합니다. shadow mode에서 pending_approval 판정은 audit로 강등되고 [shadow] would …로 로깅되므로, 보류가 실제 트래픽을 게이트하기 시작하기 전에 그것이 얼마나 자주 발동할지 측정할 수 있습니다.
이것은 위험한 툴 호출과도한 자율성을 위한 올바른 컨트롤입니다 — “사람에게 물어보라”는 판정이 allow과 deny 둘 다를 이기는 경우.

다음으로 갈 곳

Verdicts

여섯 firewall 판정 전부와 기본 판정.

게이트웨이 키

승인을 폴링하는 데 사용되는 firewall-gateway 토큰을 발행합니다.

Shadow mode

보류가 실제 트래픽을 게이트하기 전에 측정합니다.

규칙 레퍼런스

pending_approval 판정을 생성하는 규칙을 작성합니다.