Add multi-approver quorum, vote audit trail and on_timeout resolution to workflow approvals#579
Open
fernandorocagonzalez wants to merge 2 commits into
Open
Conversation
… to workflow approvals
Approval nodes get a required_approvals count (default 1, existing behavior
unchanged): each user with the approver role casts a single vote and the
node completes once enough distinct users approved. One deny always denies
the node immediately. Users cannot vote twice; the approve/deny endpoints
reject repeat votes and the UI disables the buttons via user_has_voted
while the node waits for the rest of the quorum.
Every vote is stored as a WorkflowApprovalVote with user, action, timestamp
and an optional comment (POST {"comment": ...} on approve/deny), browsable
at /api/v2/workflow_approvals/N/votes/ and filterable across workflows at
/api/v2/workflow_approval_votes/. Votes are immutable through the API and
keep denormalized approval/job/user names so the audit trail survives job
cleanup and user deletion.
Approval nodes with a timeout can now choose what the timeout means with
on_timeout: deny (default, current behavior) or approve, in which case the
task manager marks the expired node successful, still flagged timed_out
and with a job explanation saying it was automatically approved.
Contributor
There was a problem hiding this comment.
Pull request overview
This PR enhances workflow approval nodes across the API, scheduler, and UI by adding (1) multi-approver quorum support, (2) an immutable vote audit trail, and (3) configurable timeout resolution (auto-approve vs auto-deny), aligning approvals with “required reviewers” style gates.
Changes:
- Adds
required_approvals+on_timeoutfields to workflow approval templates and jobs, with UI support for configuring and displaying these values. - Introduces
WorkflowApprovalVoteas an audit log for approve/deny actions, plus new vote list/detail API endpoints and related UI display. - Updates TaskManager timeout handling so timed-out approvals can optionally resolve as successful (“approve”) instead of failed (“deny”).
Reviewed changes
Copilot reviewed 26 out of 26 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| awx/ui/src/screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.test.js | Extends detail view tests to cover quorum progress, votes rendering, and on-timeout display. |
| awx/ui/src/screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js | Fetches and displays vote audit trail; shows quorum progress and on-timeout behavior. |
| awx/ui/src/screens/WorkflowApproval/shared/WorkflowDenyButton.js | Disables deny when the user has already voted. |
| awx/ui/src/screens/WorkflowApproval/shared/WorkflowApprovalButton.js | Disables approve when the user has already voted. |
| awx/ui/src/screens/Template/WorkflowJobTemplateVisualizer/Visualizer.js | Propagates required_approvals and on_timeout into visualizer node state. |
| awx/ui/src/screens/Template/WorkflowJobTemplateVisualizer/Modals/NodeModals/useWorkflowNodeSteps.js | Populates edit defaults for approval node quorum/timeout settings. |
| awx/ui/src/screens/Template/WorkflowJobTemplateVisualizer/Modals/NodeModals/NodeTypeStep/useNodeTypeStep.js | Adds initial form values for new approval node fields. |
| awx/ui/src/screens/Template/WorkflowJobTemplateVisualizer/Modals/NodeModals/NodeTypeStep/NodeTypeStep.test.js | Adds coverage for the new approval node form inputs. |
| awx/ui/src/screens/Template/WorkflowJobTemplateVisualizer/Modals/NodeModals/NodeTypeStep/NodeTypeStep.js | Adds UI inputs for “Required approvals” and “On timeout” for approval nodes. |
| awx/ui/src/screens/Template/WorkflowJobTemplateVisualizer/Modals/NodeModals/NodeModal.test.js | Updates modal tests to include new approval node form values. |
| awx/ui/src/screens/Template/WorkflowJobTemplateVisualizer/Modals/NodeModals/NodeModal.js | Ensures non-approval nodes strip the new approval-only fields; sets defaults. |
| awx/ui/src/screens/Template/WorkflowJobTemplateVisualizer/Modals/NodeModals/NodeEditModal.js | Sends required_approvals / on_timeout to API when editing approval nodes. |
| awx/ui/src/screens/Template/WorkflowJobTemplateVisualizer/Modals/NodeModals/NodeAddModal.js | Sends required_approvals / on_timeout to API when adding approval nodes. |
| awx/ui/src/api/models/WorkflowApprovals.js | Adds client method for GET /workflow_approvals/:id/votes/. |
| awx/main/tests/functional/api/test_workflow_approval_quorum.py | Functional tests for quorum progression, veto deny, double-vote rejection, timeout behavior, and vote audit durability/visibility. |
| awx/main/scheduler/task_manager.py | Implements on_timeout=approve behavior when expiring approvals. |
| awx/main/models/workflow.py | Adds fields and vote model; records votes and applies quorum logic when approving/denying. |
| awx/main/models/init.py | Exposes WorkflowApprovalVote in the models package. |
| awx/main/migrations/0206_approval_quorum_votes.py | Migration adding quorum fields and creating the vote table. |
| awx/main/access.py | Adds access model for vote objects and prefetches votes for approvals. |
| awx/api/views/root.py | Exposes top-level API route for workflow approval votes. |
| awx/api/views/init.py | Adds comment parsing for votes; prevents double votes; adds vote list/detail views. |
| awx/api/urls/workflow_approval.py | Adds nested votes endpoint for a workflow approval. |
| awx/api/urls/workflow_approval_vote.py | Adds top-level votes list/detail endpoints. |
| awx/api/urls/urls.py | Wires vote URL module into the API router. |
| awx/api/serializers.py | Adds new serializer fields for quorum/voting state and a serializer for vote records. |
…p quorum stable when an approver is deleted, accept vote comments from any dict-like request body
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this adds
Three improvements to workflow approval nodes, aimed at closing the gap with the manual gates in Jenkins (input step) and GitHub Actions (environment required reviewers):
Multi approver quorum
Approval nodes get a
required_approvalsfield (default 1, so existing nodes behave exactly as before). When it is higher than 1, each user with the approver role casts one vote and the node only moves to successful once that many distinct users have approved. A single deny always denies the node immediately, same as GitHub Actions reviewers. Users cannot vote twice, the approve/deny endpoints return a 400 if they try, and the UI disables the buttons once you have voted while the node waits for the rest of the quorum.The approval detail endpoint and UI now show
approvals_receivednext torequired_approvalsso approvers can see how far along the node is.Vote audit trail
Every approve/deny action is recorded as a
WorkflowApprovalVoterow: who voted, what they voted, when, and an optional free text comment (POST /approve/ {"comment": "..."}). Votes are exposed at:/api/v2/workflow_approvals/N/votes//api/v2/workflow_approval_votes/(flat, filterable by user, vote, date and so on)Votes are immutable through the API and survive job cleanup and user deletion: the FKs are severed with SET_NULL and the vote keeps denormalized copies of the approval name, workflow job id/name and username, so the audit trail stays useful after the approval itself is purged. Visibility follows the workflow: you can list votes for approvals you can see, superusers and system auditors see everything including orphaned votes.
The
approved_or_denied_byfield keeps working as before, pointing at the user whose vote resolved the node.Timeout resolution
Approval nodes with a timeout get an
on_timeoutchoice (deny, the current behavior and the default, orapprove). Withapprove, when the timeout expires the task manager marks the node successful instead of failed, still flagging ittimed_outand recording an explanation saying it was automatically approved. This mirrors what Jenkins pipelines commonly do with timeout wrapped input steps.Notes
0206adds the two fields on template and job plus the vote table.required_approvals= 1 andon_timeout= 'deny' nothing changes for existing deployments; those are the defaults applied by the migration.