Approvals
When policy resolves an action to needs_approval, Suvra creates an approval record. Reviewers work through these from /dashboard/approvals.
Requires the approvals.read permission to view; approvals.decide to act.
Tabs
| Tab | Filter | Counts |
|---|---|---|
| Pending | status=pending and not expired | live count |
| Approved | status=approved | live count |
| Denied | status=denied | live count |
| All | everything (includes expired) | live count |
Each tab supports a search box (actor / action / target) and a limit control (1-500, default 100). Additional query filters: agent, environment.
Approvals table
| Column | Description |
|---|---|
| Created | UTC timestamp |
| Actor | User or agent that triggered the request |
| Action | Human-readable action title |
| Target | Path / URL / target in code format |
| Risk | Badge: low / medium / high (inferred from action type + decision) |
| Status | Badge: pending / approved / denied / expired |
| Approval ID | Truncated ID in code format |
| Actions | For pending: Approve & Execute, Approve, Deny; else "Closed" |
| Detail | Opens the detail drawer |
Detail drawer
Opens a side drawer showing:
- Decision hero with the action's risk and decision
- Summary — buyer-friendly explanation of why approval was required
- Key fields — Approval ID, Action ID, Matched Policy, Starter Pack (if any), Identity fields, Decided By, Note
- Why approval was required — bullets derived from
result_summary - Action payload — full
type+params+ identity JSON block - Drawer actions — Approve / Deny buttons (if pending and
approvals.decide)
Actions available to reviewers
Three buttons post to these CSRF-protected dashboard endpoints:
| Button | Endpoint |
|---|---|
| Approve | POST /dashboard/approvals/{approval_id}/approve |
| Deny | POST /dashboard/approvals/{approval_id}/deny |
| Approve & Execute | POST /dashboard/approvals/{approval_id}/approve_execute |
Approve records decided_by + note and flips the status — the caller still has to replay the action with meta.approval_id attached. Approve & Execute approves and immediately replays the action server-side. Deny is terminal and fails closed.
Expiration
Approvals may carry expires_at. Once past, the broker surfaces effective_status=expired and execution rejects the token. Expired approvals fail closed and cannot be revived — the caller must request a fresh one.
Reuse integrity
A previously approved token is never auto-consumed. The caller must present it again via meta.approval_id in POST /actions/execute, and Suvra re-verifies:
- actor identity
- node scope (for node-brokered approvals)
- action type
- normalized
params_hash(action params + full identity/registry context)
Any drift rejects the approval.
RBAC
- View tabs / drawers:
approvals.read(Viewer and above) - Approve / Deny / Approve & Execute:
approvals.decide(Operator, Policy Admin, Admin) - Viewers see the tabs read-only