Add duo_auto_mode cascading setting implementation behind duo_auto_mode flag
What does this MR do and why?
This MR introduces a duo_auto_mode feature flag as well as the cascading setting logic for auto mode to be enabled at the namespace/group/project instance. The UI for this setting will be handled in the next MR: Add duo_auto_mode UI toggle to Duo settings (!253317 - merged) (which was the original MR that has now been split up).
The DB changes were included in this MR: Add duo_auto_mode_enabled cascading setting dat... (!255428 - merged).
It's important to note this thread for implementation details pertaining to read/write cascading settings. This setting is a read cascade setting which normally don't have defaults, but that is now a legacy pattern. While a fix is being created, the work around is to include a reset_duo_auto_mode_to_inherit_from_namespace method which is in create-service.rb. Here is the MR to close this gap in the future: Refactor duo cascading defaults into a single d... (!255492 - merged).
References
Partially closes: Auto mode: duo_auto_mode cascading setting, cap... (#618088 - closed).
Related to auto mode
Screenshots or screen recordings
| Before | After |
|---|---|
How to set up and validate locally
How to set up and validate locally 🤖 Generated (GDK)
Prerequisites
- A GDK running EE (all the code is under
ee/). - A license with AI features (the REST
direct_accesspath needsai_workflows+duo_features_enabled; the project mutation needs an active Duo add-on or SaaS emulation). duo_auto_modeisdefault_enabled: false, so it is off on a GDK until you enable it.- The Duo Workflow Service does not need to be running:
duo_auto_modeis a Rails-computed capability appended locally.
Out of scope: this branch also touches
ee/app/services/ai/tool_rules/resolution_service.rb/ee/lib/ai/tool_rules/permissions.rb(alocal_surface?governance relaxation gated by the separateduo_workflow_local_tool_governanceflag). That is a separate concern and is not part of validatingduo_auto_mode.
1. Enable the feature flag
# Rails console. The flag is checked against `project || namespace`.
Feature.enable(:duo_auto_mode) # instance-wide (simplest)
Feature.enable(:duo_auto_mode, group) # or per-actor
Feature.enable(:duo_auto_mode, project)In RSpec, WIP flags default to enabled, which is why the specs assert the capability without enabling it. On a GDK you must enable it explicitly.
2. Set the cascading setting
duo_auto_mode_enabled (+ lock_duo_auto_mode_enabled) is a cascading_attr at instance/group/project, with a three-state duo_auto_mode_availability accessor (default_on / default_off / never_on).
# Instance (ApplicationSetting)
s = ApplicationSetting.current
s.duo_auto_mode_availability = :default_on # duo_auto_mode_enabled=true, lock=false
s.save!
# Group (namespace_settings)
group = Group.find_by_full_path('my-group')
group.namespace_settings.update!(duo_auto_mode_enabled: true)
group.namespace_settings.duo_auto_mode_enabled? # cascading reader (walks ancestors + instance)
group.namespace_settings.duo_auto_mode_enabled_locked?
# Project (project_settings)
project = Project.find_by_full_path('my-group/my-project')
project.project_setting.update!(duo_auto_mode_enabled: true)
project.project_setting.duo_auto_mode_enabled?
# Effective value with project-wins precedence
Ai::DuoSettings::CascadingSettingResolver.enabled?(project: project, namespace: group, &:duo_auto_mode_enabled?)3. Verify the capability is advertised
The duo_auto_mode capability is advertised in two mirrored places, both gated on flag AND effective setting: GraphQL aiFlowsMetadata (Ai::FlowsMetadataService) and REST direct_access (Api::Ai::DuoWorkflows::Workflows#compute_server_capabilities).
# http://gdk.test:3000/-/graphql-explorer (use projectId to test project scope; project wins when both are given)
query {
aiFlowsMetadata(namespaceId: "gid://gitlab/Namespace/123") {
capabilities { name metadata }
}
}With flag + setting ON, duo_auto_mode appears in capabilities; with the flag off, the setting off/never_on, or no setting in scope, the duo_auto_mode entry is simply absent.
# REST direct_access (token needs ai_workflows scope) -> server_capabilities includes "duo_auto_mode"
curl --request POST --header "PRIVATE-TOKEN: <token>" \
"http://gdk.test:3000/api/v4/ai/duo_workflows/direct_access?namespace_id=123"4. Verify write-cascade + new-project inheritance
# Group -> descendants cascade (Namespaces::CascadeDuoSettingsWorker)
group = Group.find_by_full_path('my-group')
project = Project.find_by_full_path('my-group/my-project')
Sidekiq::Testing.inline! do
Groups::UpdateService.new(group, group.owners.first, { duo_auto_mode_enabled: true }).execute
end
project.project_setting.reload.duo_auto_mode_enabled # => true (cascaded down)
# New project inherits from its group (reset_duo_auto_mode_to_inherit_from_namespace)
group.namespace_settings.update!(duo_auto_mode_enabled: true)
p = Projects::CreateService.new(group.owners.first,
{ namespace_id: group.id, name: 'inherit-check', path: 'inherit-check' }).execute
p.project_setting.duo_auto_mode_enabled # => true (inherited on create)Instance-level changes cascade via AppConfig::CascadeDuoSettingsWorker.
5. Specs
bin/rspec ee/spec/models/namespace_setting_spec.rb ee/spec/models/ee/project_setting_spec.rb ee/spec/models/application_setting_spec.rb
bin/rspec ee/spec/services/ai/flows_metadata_service_spec.rb ee/spec/services/ai/cascade_duo_settings_service_spec.rb
bin/rspec ee/spec/requests/api/ai/duo_workflows/workflows_spec.rb ee/spec/requests/api/ai/duo_workflows/cascading_settings_spec.rb
bin/rspec ee/spec/graphql/ee/mutations/groups/update_spec.rb
# add `-e "duo_auto_mode"` to target only the relevant examplesNo jest is required for this MR (backend-only slice).
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.