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_context resolves callback_hook_id only through Ai::DuoWorkflows::CallbackHooksFinder.
  • That finder returns project and ancestor-group hooks with duo_flow_callback_enabled: true.
  • The flow_callbacks create path never sets duo_flow_callback_enabled, and a FlowCallbackHook is 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.rb
  • ee/app/models/ai/duo_workflows/flow_callback_hook.rb
  • ee/lib/api/entities/ai/duo_workflows/flow_callback_hook.rb
  • ee/spec/requests/api/ai/duo_workflows/flow_callbacks_spec.rb
  • ee/spec/models/ai/duo_workflows/flow_callback_hook_spec.rb
  • ee/spec/factories/ai/duo_workflows/flow_callback_hooks.rb
  • config/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 — drop mount ::API::Ai::DuoWorkflows::FlowCallbacks
  • ee/app/policies/ee/organizations/organization_policy.rb — drop the three enable :create_duo_flow_callback_hook / :read_… / :delete_… abilities
  • ee/spec/policies/organizations/organization_policy_spec.rb — drop the matching describe 'duo_flow_callback_hook abilities' block
  • db/docs/web_hooks.yml — drop Ai::DuoWorkflows::FlowCallbackHook from classes
  • doc/api/duo_agent_platform_flows.md — remove the four sections "Register / List / Get / Delete a flow callback endpoint", then regenerate doc/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_callbacks endpoints return 404.
  • git grep -n "FlowCallbackHook\|flow_callbacks" is clean outside doc-locale/.
  • Post-deploy migration removes the orphaned rows, with a migration spec.
  • Deprecation entry added and doc/update/deprecations.md regenerated.
  • 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.

Edited by Thomas Schmidt