You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 8efa395
Browse filesBrowse the repository at this point in the historyBrowse files
feat(approvals): gate declared decision actions on a server-computed viewer capability (#3344)
`getRequest` / `listRequests` now attach a per-viewer block to each row from the
caller's context — `viewer: { can_act, is_submitter }` (ApprovalRequestRow):
- can_act — the caller is a current pending approver (their user id is in
the resolved pending_approvers while status is pending). This is
the exact check the decision methods authorize with, so it
already reflects position/team/manager resolution.
- is_submitter — the caller submitted the request.
The declared decision actions on sys_approval_request now gate their `visible`
CEL on it: approver actions (approve/reject/reassign/send-back/request-info) use
`record.viewer.can_act`; submitter levers (remind/recall/resubmit) use
`record.viewer.is_submitter`. Before this, approver actions only trimmed the
non-pending case, so a submitter viewing their own pending request saw buttons
they couldn't use (the backend 403'd), and a position-addressed approver could
be wrongly hidden by a client-side identity heuristic. Where `viewer` is absent
(a row surfaced outside a service read with a user context), the predicate fails
closed.
Tests: getRequest returns can_act true for a pending approver, false for the
submitter and strangers, and false once finalized; listRequests attaches viewer
to every row; the object contract test pins the new predicates.
Claude-Session: https://claude.ai/code/session_016ypkQikZ55oWUHUnMebwXA
Co-authored-by: Claude <noreply@anthropic.com>
0 commit comments