diff --git a/ee/app/policies/ee/global_policy.rb b/ee/app/policies/ee/global_policy.rb index 14da53c1d1c3e3e1bf6b94535a5135b79e5da9c9..1b0846d35594bf75b6b49789f7b9a9ea14a41624 100644 --- a/ee/app/policies/ee/global_policy.rb +++ b/ee/app/policies/ee/global_policy.rb @@ -94,6 +94,8 @@ module GlobalPolicy if duo_chat_self_hosted? self_hosted_models_available_for?(@user) + elsif ::Feature.enabled?(:duo_chat_allowed_to_use, @user) + user.allowed_to_use?(:duo_chat) else duo_chat.allowed_for?(@user) end diff --git a/ee/config/feature_flags/gitlab_com_derisk/duo_chat_allowed_to_use.yml b/ee/config/feature_flags/gitlab_com_derisk/duo_chat_allowed_to_use.yml new file mode 100644 index 0000000000000000000000000000000000000000..cb642203fb369423f7b2356dc39471ba7ff64a2a --- /dev/null +++ b/ee/config/feature_flags/gitlab_com_derisk/duo_chat_allowed_to_use.yml @@ -0,0 +1,9 @@ +--- +name: duo_chat_allowed_to_use +feature_issue_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/183834 +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/183843 +rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/523874 +milestone: '17.10' +group: group::duo chat +type: gitlab_com_derisk +default_enabled: false diff --git a/ee/spec/policies/global_policy_spec.rb b/ee/spec/policies/global_policy_spec.rb index 585f4e8f83b74d72932f41c79dae2d45250934eb..5c48c73c792567f2872f0b49662441f230ccedd1 100644 --- a/ee/spec/policies/global_policy_spec.rb +++ b/ee/spec/policies/global_policy_spec.rb @@ -688,15 +688,32 @@ with_them do before do - duo_chat_service_data = instance_double(CloudConnector::SelfSigned::AvailableServiceData) - allow(CloudConnector::AvailableServices).to receive(:find_by_name).with(:duo_chat).and_return( - duo_chat_service_data - ) - allow(duo_chat_service_data).to receive(:allowed_for?).with(current_user).and_return(duo_pro_seat_assigned) + allow(current_user).to receive(:allowed_to_use?).and_return(duo_pro_seat_assigned) end it { is_expected.to duo_chat_enabled_for_user } end + + context 'when duo_chat_allowed_to_use is disabled' do + where(:duo_pro_seat_assigned, :duo_chat_enabled_for_user) do + true | be_allowed(policy) + false | be_disallowed(policy) + end + + with_them do + before do + stub_feature_flags(duo_chat_allowed_to_use: false) + + duo_chat_service_data = instance_double(CloudConnector::SelfSigned::AvailableServiceData) + allow(CloudConnector::AvailableServices).to receive(:find_by_name).with(:duo_chat).and_return( + duo_chat_service_data + ) + allow(duo_chat_service_data).to receive(:allowed_for?).with(current_user).and_return(duo_pro_seat_assigned) + end + + it { is_expected.to duo_chat_enabled_for_user } + end + end end context 'when not on .org or .com' do @@ -711,15 +728,38 @@ before do allow(::Gitlab).to receive(:org_or_com?).and_return(false) stub_ee_application_setting(lock_duo_features_enabled: lock_duo_features_enabled) - duo_chat_service_data = instance_double(CloudConnector::SelfSigned::AvailableServiceData) - allow(CloudConnector::AvailableServices).to receive(:find_by_name).with(:duo_chat).and_return( - duo_chat_service_data - ) - allow(duo_chat_service_data).to receive(:allowed_for?).with(current_user).and_return(duo_pro_seat_assigned) + allow(current_user).to receive(:allowed_to_use?).and_return(duo_pro_seat_assigned) end it { is_expected.to duo_chat_enabled_for_user } end + + context 'when duo_chat_allowed_to_use is disabled' do + where(:lock_duo_features_enabled, :duo_pro_seat_assigned, :duo_chat_enabled_for_user) do + true | true | be_disallowed(policy) + true | false | be_disallowed(policy) + false | false | be_disallowed(policy) + false | true | be_allowed(policy) + end + + with_them do + before do + stub_feature_flags(duo_chat_allowed_to_use: false) + + allow(::Gitlab).to receive(:org_or_com?).and_return(false) + stub_ee_application_setting(lock_duo_features_enabled: lock_duo_features_enabled) + allow(current_user).to receive(:allowed_to_use?).and_return(duo_pro_seat_assigned) + + duo_chat_service_data = instance_double(CloudConnector::SelfSigned::AvailableServiceData) + allow(CloudConnector::AvailableServices).to receive(:find_by_name).with(:duo_chat).and_return( + duo_chat_service_data + ) + allow(duo_chat_service_data).to receive(:allowed_for?).with(current_user).and_return(duo_pro_seat_assigned) + end + + it { is_expected.to duo_chat_enabled_for_user } + end + end end context 'when duo chat is self hosted' do @@ -738,12 +778,9 @@ :self_hosted?).and_return(self_hosted) self_hosted_service_data = instance_double(CloudConnector::SelfSigned::AvailableServiceData) - duo_chat_service_data = instance_double(CloudConnector::SelfSigned::AvailableServiceData) allow(CloudConnector::AvailableServices).to receive(:find_by_name).with(:self_hosted_models) .and_return(self_hosted_service_data) - allow(CloudConnector::AvailableServices).to receive(:find_by_name).with(:duo_chat) - .and_return(duo_chat_service_data) - allow(duo_chat_service_data).to receive(:allowed_for?).with(current_user).and_return(allowed_to_use) + allow(current_user).to receive(:allowed_to_use?).and_return(allowed_to_use) allow(self_hosted_service_data).to receive(:allowed_for?).with(current_user).and_return(allowed_to_use) allow(self_hosted_service_data).to receive(:free_access?).and_return(free) end @@ -770,6 +807,8 @@ stub_licensed_features(ai_chat: true, amazon_q: true) stub_feature_flags(amazon_q_chat_and_code_suggestions: ff_enabled) + allow(current_user).to receive(:allowed_to_use?).with(:duo_chat).and_return(false) + allow(current_user).to receive(:allowed_to_use?).with(:duo_chat, service_name: :amazon_q_integration, licensed_feature: :amazon_q).and_return(allowed_to_use) end