Resolve Duo tool approvals from the Slack review modal
What does this MR do and why?
Third of three MRs that let a user approve or deny a paused Duo agent's tool call from Slack. This one applies the decision submitted through the review modal.
DuoToolApprovalModalSubmitServicehandles the modal'sview_submission: reads the Approve / Deny choice andworkflow_id:fingerprintfromprivate_metadata, resolves the Slack user, and callsResolveToolApprovalService.ResolveToolApprovalServiceis the security gate: only the session owner, only with liveupdate_duo_workflowpermission, only while the fingerprint still matches the pending request, serialized under a lease. Then the run resumes viaExecuteRunServiceand the decision is audited (duo_tool_call_approved/duo_tool_call_denied) and tracked (ai_duo_messaging_tool_approval_resolved).- On success the channel message is updated in place via
pending_approval_tsso the Review button disappears, and the modal swaps to the outcome. Refusals swap the modal to a notice saying why (not owner, already answered, unavailable). - The session's status and checkpoint only change once the runtime picks the run up, so a second submission in that window would otherwise pass the fingerprint check and dispatch a second resume. The applied decision is recorded as
answered_approvalin the callback context, checked under the lease after reloading the row from the primary. - The callback context's
status_tsis left alone, so the resumed run keeps editing the reply the user is already reading rather than posting a new message (see !257339 (merged)).
The Review click in the previous MR only decided what to show; a modal payload is not proof of anything, so everything is re-checked here.
Resuming goes through ExecuteRunService, which landed in !256183 (merged) (#628435). This MR was stacked on that branch and has been rebased onto master now that it is merged. Behind the default-off slack_duo_api_flow flag.
Stack:
- Foundations — !255536 (merged) (merged)
- Post the request and open the review modal — !255537 (merged) (merged)
- This MR — resolve the decision
Split out of !254849 (closed).
Nothing pauses a real Slack session yet: the slack_assistant flow has no approval nodes and pre-approves every privilege it holds. Those switches are sequenced after this MR on purpose (a pending approval has no timeout, so turning them on first would strand sessions). In flight:
- #629377 — make admin tool approval rules take effect for Duo in Slack (
require_tool_approval,allow_agent_to_request_user); see also #629377 (comment 3884544167) on which governance column Slack should live in - !256214 (merged) — stop pre-approving write actions for
slack_assistant/v1 - gitlab-org/modelops/applied-ml/code-suggestions/ai-assist!7008 (merged) — DWS reports the awaiting status before the checkpoint is saved, so
on_approval_requiredcan find no pending request and never post the Review button
References
Screenshots or screen recordings
Slack only; no changes to the GitLab web UI.
| Demo |
|---|
How to set up and validate locally
End to end, with a real session. Prerequisites: GitLab for Slack installed on the GDK with the bot token, your Slack user linked (ChatName), Slack events and interactions reaching the GDK (tunnel or Socket Mode), slack_assistant/v1 enabled for the group, Feature.enable(:slack_duo_api_flow).
Until the items listed under "In flight" above land, three local changes make a session pause on create_issue:
-
GDK AI gateway,
duo_workflow_service/agent_platform/v1/flows/configs/slack_assistant/1.0.0.yml: addrequire_tool_approval: trueto theslack_agentcomponent, thengdk restart duo-workflow-service. (Tracked in #629377.) -
ee/app/services/ai/messaging/adapters/base.rb,start_workhorse_flow: passpre_approved_agent_privileges: flow.agent_privileges - [AgentPrivileges::READ_WRITE_GITLAB], thengdk restart rails-background-jobs. (What !256214 (merged) does properly.) -
The DWS status-before-checkpoint race (gitlab-org/modelops/applied-ml/code-suggestions/ai-assist!7008 (merged)) means the Review message is usually not posted by the worker. Either apply gitlab-org/modelops/applied-ml/code-suggestions/ai-assist!7008 (merged) to the gateway, or re-fire the hook once the session is paused:
w = Ai::DuoWorkflows::Workflow.order(:id).last # status tool_call_approval_required ctx = w.messaging_callback_context Ai::Messaging::Adapters::Slack.from_callback_context(ctx).on_approval_required(callback_context: ctx, workflow: w)
Then, in Slack: @Duo create an issue in <group>/<project> titled "Demo" with a short description.
MR acceptance checklist
Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.