Code Suggestions still work on GitLab.com when group Duo availability is set to "Always Off"
Summary
On GitLab.com (SaaS), a group Owner setting GitLab Duo availability to "Always Off" (never_on) does not disable Code Suggestions for that group's members. Members continue to receive Code Suggestions, and the resulting Duo Agent Platform / AI Gateway usage is counted towards the customer's credit usage, despite the group being explicitly set to "Always Off". A customer reported unexpected credit usage traced to Code Suggestions under exactly this configuration.
This behavior is a known gap discussed in #535507 (moved): "Always Off" acts as a true kill switch on self-managed instances, but on GitLab.com it only controls context access rather than gating feature (and credit) usage.
Steps to reproduce
- On GitLab.com, have a top-level group on a plan with a Duo add-on (Duo Pro/Enterprise) assigned to users.
- As a group Owner, go to Settings > GitLab Duo and set GitLab Duo availability to Always Off.
- As a member of that group with a Duo seat, open a project in a supported IDE and trigger Code Suggestions.
- Observe that Code Suggestions still return completions.
- Check Duo usage for the namespace.
What is the current bug behavior?
Code Suggestions remain functional and count towards credit usage even though group-level Duo availability is set to "Always Off". The "Always Off" toggle gives group Owners the reasonable expectation of a kill switch, but on SaaS it does not stop Code Suggestions or the associated credit usage.
What is the expected correct behavior?
When a group's Duo availability is set to "Always Off" on GitLab.com, Code Suggestions should be disabled for that group's members and no credit usage should be recorded, matching the kill-switch behavior on self-managed instances (or the difference should be clearly documented and surfaced).
Relevant logs and/or screenshots
N/A — customer-reported credit usage attributed to Code Suggestions.
Possible fixes
The root cause is that the access_code_suggestions policy only checks the instance-level duo_never_on?, never the namespace-level setting.
In ee/app/policies/ee/global_policy.rb, ai_features_banned reads the instance setting:
condition(:ai_features_banned) do
::Gitlab::CurrentSettings.duo_never_on?
end
rule do
code_suggestions_licensed & ~ai_features_banned & code_suggestions_enabled_for_user
end.enable :access_code_suggestionsAnd duo_never_on? in ee/app/models/ee/application_setting.rb reads only the instance value:
def duo_never_on?
duo_availability == :never_on
endOn SaaS there is no instance admin setting duo_availability = never_on, so this always returns false. A group Owner's "Always Off" writes never_on to NamespaceSetting.duo_availability (delegated from Group in ee/app/models/ee/group.rb: delegate :duo_availability, ... to: :namespace_settings), but access_code_suggestions is a global/user policy that never consults the namespace setting. The group- and project-scoped ai_features_banned conditions in ee/app/policies/ee/group_policy.rb and ee/app/policies/ee/project_policy.rb also delegate to the same instance-level check, so they do not close the gap either.
Fix options:
- Make the Code Suggestions availability check honor a namespace-level
never_onfor the relevant group(s) on SaaS, not just the instance setting. - Alternatively, if the divergent behavior is intended, clearly document it and surface the blocking reason to users/admins.
Related discussion: #535507 (moved).