Remove the organization-scoped Duo flow callback registration API
Why
master has two ways to register a Duo flow callback endpoint, and only one of them works.
| Model | Added by | State |
|---|---|---|
POST /ai/duo_workflows/flow_callbacks, backed by the organization-scoped Ai::DuoWorkflows::FlowCallbackHook |
!247573 (merged), shipped in 19.3 | Registration only, no delivery path |
duo_flow_callback_enabled on a normal project or group webhook |
!249141 (merged), !249145 (merged), !249147 (merged), !249149 (merged) | Complete, behind duo_flow_callback_hooks |
!247573 (merged) deliberately shipped registration only and deferred delivery to a follow-up, which became draft !248060 (closed). That follow-up was superseded: it was re-split into the MR stack that landed for this epic, and that stack took the project/group webhook route instead. The organization-scoped model was never wired up:
API::Ai::DuoWorkflows::Workflows#build_messaging_callback_contextresolvescallback_hook_idonly throughAi::DuoWorkflows::CallbackHooksFinder.- That finder returns project and ancestor-group hooks with
duo_flow_callback_enabled: true. - The
flow_callbackscreate path never setsduo_flow_callback_enabled, and aFlowCallbackHookis organization-scoped, so it can never fall inside the finder's scope.
So an ID returned by that API is rejected with 400 at trigger time, while doc/api/duo_agent_platform_flows.md tells readers to pass it as callback_hook_id. This was established by reading the code, not by running it — worth confirming on a GDK early in the work.
Agent Developer owns the implementation of this epic and has agreed with the AutoFlow team to take the feature over, so we keep one registration model: the project or group webhook.
What to remove
Delete:
ee/lib/api/ai/duo_workflows/flow_callbacks.rbee/app/models/ai/duo_workflows/flow_callback_hook.rbee/lib/api/entities/ai/duo_workflows/flow_callback_hook.rbee/spec/requests/api/ai/duo_workflows/flow_callbacks_spec.rbee/spec/models/ai/duo_workflows/flow_callback_hook_spec.rbee/spec/factories/ai/duo_workflows/flow_callback_hooks.rbconfig/authz/permissions/duo_flow_callback_hook/(create.yml,read.yml,delete.yml,.metadata.yml)config/authz/permission_groups/assignable_permissions/duo/duo_flow_callback_hook/(create.yml,read.yml,delete.yml)
Edit:
ee/lib/ee/api/api.rb— dropmount ::API::Ai::DuoWorkflows::FlowCallbacksee/app/policies/ee/organizations/organization_policy.rb— drop the threeenable :create_duo_flow_callback_hook/:read_…/:delete_…abilitiesee/spec/policies/organizations/organization_policy_spec.rb— drop the matchingdescribe 'duo_flow_callback_hook abilities'blockdb/docs/web_hooks.yml— dropAi::DuoWorkflows::FlowCallbackHookfromclassesdoc/api/duo_agent_platform_flows.md— remove the four sections "Register / List / Get / Delete a flow callback endpoint", then regeneratedoc/api/openapi/openapi_v3.yaml
What to leave alone
Keep the working path untouched: the duo_flow_callback_enabled column, CallbackHooksFinder, Ai::Messaging::Adapters::Webhook, Ai::Messaging::WebhookDeliveryWorker, and the duo_flow_callback_hooks feature flag. This issue removes only the organization-scoped registration surface. doc-locale/ is translated and regenerated separately, so leave it.
Data cleanup
Rows created by the API carry type = 'Ai::DuoWorkflows::FlowCallbackHook' in web_hooks. Once the class is gone, loading such a row is expected to raise ActiveRecord::SubclassNotFound, and Ai::Messaging::Adapters::Webhook#find_hook loads by ID through WebHook.find_by_id. So the rows cannot simply be left behind.
Reproduce that failure mode locally first, then add a post-deploy migration that removes the affected rows and their web_hook_logs. If deletion turns out to be the wrong call, a type rewrite is the alternative — decide with evidence, and add a migration spec either way. Check the row count on GitLab.com before writing the migration: delivery never existed, so any rows are inert registrations, but the number is worth knowing.
Deprecation announcement
The endpoints shipped in 19.3 and are documented with no Status: Experiment marker, so removal is a breaking change under the deprecation guidelines. Add an entry to data/deprecations/ following data/deprecations/templates/example.yml, then run bundle exec rake gitlab:docs:compile_deprecations to regenerate doc/update/deprecations.md.
Use reporter: thomas-schmidt, stage: Agent Foundations, and this issue for issue_url. Impact is low: no delivery path ever existed, so no integration can be receiving callbacks today.
Acceptance criteria
- All four
/ai/duo_workflows/flow_callbacksendpoints return404. -
git grep -n "FlowCallbackHook\|flow_callbacks"is clean outsidedoc-locale/. - Post-deploy migration removes the orphaned rows, with a migration spec.
- Deprecation entry added and
doc/update/deprecations.mdregenerated. - The working path still passes:
bundle exec rspec ee/spec/finders/ai/duo_workflows/callback_hooks_finder_spec.rb ee/spec/services/ai/messaging/adapters/webhook_spec.rb ee/spec/workers/ai/messaging/webhook_delivery_worker_spec.rb spec/models/hooks/web_hook_spec.rb ee/spec/policies/organizations/organization_policy_spec.rb
Follow-ups
CD issues #607031 (rate limiting), #607034 (auto-disable) and #607035 (payload versioning) all target the removed model. They need re-pointing at the webhook path or closing once this lands; their epic &22941 is closed while they are still open. Handled separately in &22923, not here.