Skip to main content

Approvals and human oversight

This page describes the approval workflow of the Navin Platform (human in the loop): who requests, who approves, how quorum and expiry apply, how an agent run waits for a decision, and every four eyes rule found in the code. Code: services/control-plane/src/eai/domains/approvals, migration sql/postgres/V041.

Version française : ../approvals.md

Lifecycle of an approval​

StatusMeaning
pendingWaiting for decisions
approvedThe number of approvals reaches the quorum
rejectedAn approver rejected
expiredexpires_at passed without a final decision
cancelledCancelled with POST /v1/approvals/{approval_id}/cancel
  • Request: POST /v1/approvals (roles tenant_admin, developer, agent, security_officer, finops) with the action, the resource, a reason, a quorum from 1 to 10, approver_roles and a duration expires_in_seconds. Default duration: EAI_APPROVAL_TTL_SECONDS (86400 s). An idempotency key avoids duplicates.
  • Read: GET /v1/approvals, GET /v1/approvals/{approval_id} (tenant members).
  • Decision: POST /v1/approvals/{approval_id}/decide with approve or reject and a comment. Admitted roles: the approver_roles of the request, else tenant_admin, security_officer, developer, business_owner.
  • Expiry: the approvals worker job (EAI_WORKER_APPROVAL_EXPIRY_INTERVAL_SECONDS) moves overdue requests to expired; a request read after its deadline is expired too.

Separation of duties​

The eai.domains.approvals.service service refuses that the same person requests and approves:

  • the requester, the user the agent acts for (on_behalf_of) and every excluded_approvers of the request never decide: 403 separation_of_duties, denial audited (approval.decide deny);
  • an approver decides only once: 409 already_decided; the quorum only counts distinct people;
  • a closed request answers 409 approval_closed;
  • an action that needs an approval checks its state (require_approved): 403 approval_required until it is approved.

Approval of an agent run​

  1. The agent manifest lists its sensitive actions in autonomy.human_approval_for (patterns tool:<name>, agent:<name>, model:<name> or a bare name).
  2. A matching tool_call, subagent, model_call or act step without approval_id is recorded pending and a run.<kind> approval is opened; an agent may also request an approval step with its own quorum (run.approval).
  3. The run moves to waiting_approval.
  4. On the decision, the run resumes (running, reason approval_granted) or fails (failed, reason approval_rejected or approval_expired).
  5. A step replayed with an approval_id is accepted only when the approval is approved for that run.

The OPA policy may also require an approval through an approval obligation (authentication-authorization.md), and the SOC may apply the REQUIRE_APPROVAL reaction.

Controlled promotions​

Moving a resource to approved or active opens a promotion approval (eai.domains.approvals.promotion). Once approved, the platform checks the risk classification (a high risk system needs an approved risk assessment), runs the blocking evaluation suites of the target and applies the status only when everything passes. Retirements (deprecated, retired, blocked, suspended, restricted) stay immediate and audited. A model version goes through POST /v1/models/{model_id}/versions/{version}/approval.

Change path​

Every change of a prompt, skill, connector, rule, model, policy, tool, agent or pack follows the stages draft, test, security_review, business_approval, staging, production, monitoring (sql/postgres/V192, GET /v1/marketplace/changes, POST /v1/marketplace/changes/{change_id}/advance).

TransitionCondition
security_review to business_approvalApproval change.security_review by a security officer
business_approval to stagingApproval change.business_approval by a tenant administrator
staging to productionStaging smoke tests passed, then approval change.production by two people

The author never approves; every transition is kept in history and audited.

Four eyes rules​

WorkflowRuleCode or route
Break glassTwo distinct approvers (security_officer or tenant_admin), never the requester nor the beneficiaryPOST /v1/break-glass
Scheduled agent mandateApproved by someone other than the requesterPOST /v1/mandates
Recovery after a kill switchTwo distinct SOC leads, other than the requester, then reauthorizationPOST /v1/soc/recoveries/{recovery_id}/approve
Containment orderEMERGENCY_LOCKDOWN and SUSPEND_TENANT always, manual order above a blast radius of 25: second personPOST /v1/soc/orders/{order_id}/approve
Release of an audit legal holdTwo distinct approvers, each with a reason (409 audit_hold_same_approver)POST /v1/evidence/holds/{hold_id}/release
Risk exceptionThe named approver is not the author (409 separation_of_duties)POST /v1/risk/exceptions
Backup restoreTwo approvers other than the requester (Navin Manager rule)POST /v1/platform-manager/backup/restores/{plan_id}/approve
DR exerciseApproval in the Navin Manager, self approval refusedPOST /v1/platform-manager/dr/exercises/{exercise_id}/approve
Production release of a changeApproval change.production by two peoplePOST /v1/marketplace/changes/{change_id}/advance

Evidence​

  • Every creation, decision, denial, cancellation and expiry is an audit event (approval.* actions, forwarded to the SIEM by default with EAI_SIEM_FORWARD_ACTIONS).
  • Individual decisions are in eai.approval_decisions (approver, decision, comment).
  • Audit events written under a verified identity context carry approvals.approval_ids (identity-context-delegation.md).
  • The EAI-HUM-01 control of the risk catalogue ("Human oversight and approvals for sensitive actions") has approvals as its evidence source (risk-compliance.md).