Human Approvals¶
The approval system enables human-in-the-loop workflows. Sensitive actions are held pending until a human approves or rejects them via signed URLs.
How It Works¶
sequenceDiagram
participant C as Client
participant G as Gateway
participant S as State Store
participant H as Human Reviewer
C->>G: Dispatch sensitive action
G->>S: Create approval record
G-->>C: PendingApproval (approve_url, reject_url)
G->>H: Send notification with URLs
alt Approved
H->>G: POST /approve (HMAC-signed)
G->>G: Execute original action
G->>S: Update approval status
else Rejected
H->>G: POST /reject (HMAC-signed)
G->>S: Update approval status
else Expired
Note over G,S: TTL expires
G->>S: Mark as expired
end - An action matching a
require_approvalrule creates an approval record - HMAC-signed approve/reject URLs are generated
- A notification is sent to reviewers
- The action is held until approved, rejected, or expired
Rule Configuration¶
rules/approvals.yaml
rules:
- name: approve-production-deploys
priority: 1
description: "Production deployments require human approval"
condition:
all:
- field: action.action_type
eq: "deploy"
- field: action.metadata.environment
eq: "production"
action:
type: require_approval
message: "Production deployment requires approval"
ttl_seconds: 3600
Parameters¶
| Parameter | Type | Required | Description |
|---|---|---|---|
message | string | Yes | Message shown to the reviewer |
ttl_seconds | u64 | No | Time before the approval expires (default: 1 hour) |
notification_targets | list | No | Where to send approval notifications |
auto_approve_conditions | list | No | Conditions for automatic approval |
Response¶
{
"outcome": "pending_approval",
"approval_id": "apr-abc123",
"expires_at": "2026-01-15T11:00:00Z",
"approve_url": "/v1/approvals/ns/tenant-1/apr-abc123/approve?sig=...",
"reject_url": "/v1/approvals/ns/tenant-1/apr-abc123/reject?sig=...",
"notification_sent": true
}
Approval URLs¶
Approval and rejection URLs are HMAC-signed to prevent tampering. The signature includes:
- Namespace and tenant
- Approval ID
- Expiration timestamp
- Action: "approve" or "reject"
Approving an Action¶
curl -X POST "http://localhost:8080/v1/approvals/ns/tenant-1/apr-abc123/approve?sig=SIGNATURE&expires_at=TIMESTAMP"
Rejecting an Action¶
curl -X POST "http://localhost:8080/v1/approvals/ns/tenant-1/apr-abc123/reject?sig=SIGNATURE&expires_at=TIMESTAMP"
API Endpoints¶
List Pending Approvals¶
Get Approval Status¶
Approval States¶
stateDiagram-v2
[*] --> Pending: Action requires approval
Pending --> Approved: Human approves
Pending --> Rejected: Human rejects
Pending --> Expired: TTL expires
Approved --> [*]: Action executed
Rejected --> [*]: Action dropped
Expired --> [*]: Action dropped Client SDK Support¶
// Approve
client.approve("ns", "tenant-1", "apr-abc123", "sig", "expires_at").await?;
// Reject
client.reject("ns", "tenant-1", "apr-abc123", "sig", "expires_at").await?;
// List pending
let approvals = client.list_approvals("ns", "tenant-1").await?;
// Get status
let status = client.get_approval("ns", "tenant-1", "apr-abc123").await?;
Use Cases¶
- Production deployments — require team lead approval
- Financial transactions — require manager sign-off above threshold
- Data deletion — require compliance team approval
- Access grants — require security team approval