diff --git a/.rubocop_todo/gitlab/bounded_contexts.yml b/.rubocop_todo/gitlab/bounded_contexts.yml index 7f68b931863fbcb3a62654d05976b0e2cf7b62f2..d4b7c859060e36de9e58802ceef13edb132aa595 100644 --- a/.rubocop_todo/gitlab/bounded_contexts.yml +++ b/.rubocop_todo/gitlab/bounded_contexts.yml @@ -2283,7 +2283,9 @@ Gitlab/BoundedContexts: - 'ee/app/graphql/mutations/iterations/update.rb' - 'ee/app/graphql/mutations/member_roles/base.rb' - 'ee/app/graphql/mutations/member_roles/create.rb' - - 'ee/app/graphql/mutations/member_roles/create_admin.rb' + - 'ee/app/graphql/mutations/member_roles/admin/base.rb' + - 'ee/app/graphql/mutations/member_roles/admin/create.rb' + - 'ee/app/graphql/mutations/member_roles/admin/update.rb' - 'ee/app/graphql/mutations/member_roles/delete.rb' - 'ee/app/graphql/mutations/member_roles/update.rb' - 'ee/app/graphql/mutations/quality_management/test_cases/create.rb' diff --git a/doc/api/graphql/reference/_index.md b/doc/api/graphql/reference/_index.md index 05a118d40d1fd63602b54cc8955f2c5e659ba34c..ed91f3ca4b2cf0432962645e65020fcb2fcab45b 100644 --- a/doc/api/graphql/reference/_index.md +++ b/doc/api/graphql/reference/_index.md @@ -7644,7 +7644,7 @@ Input type: `MemberRoleAdminCreateInput` | <a id="mutationmemberroleadmincreateclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. | | <a id="mutationmemberroleadmincreatedescription"></a>`description` | [`String`](#string) | Description of the member role. | | <a id="mutationmemberroleadmincreatename"></a>`name` | [`String`](#string) | Name of the member role. | -| <a id="mutationmemberroleadmincreatepermissions"></a>`permissions` | [`[MemberRoleAdminPermission!]!`](#memberroleadminpermission) | List of all customizable admin permissions. | +| <a id="mutationmemberroleadmincreatepermissions"></a>`permissions` | [`[MemberRoleAdminPermission!]`](#memberroleadminpermission) | List of all customizable admin permissions. | #### Fields @@ -7652,7 +7652,34 @@ Input type: `MemberRoleAdminCreateInput` | ---- | ---- | ----------- | | <a id="mutationmemberroleadmincreateclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. | | <a id="mutationmemberroleadmincreateerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. | -| <a id="mutationmemberroleadmincreatememberrole"></a>`memberRole` | [`AdminMemberRole`](#adminmemberrole) | Created member role. | +| <a id="mutationmemberroleadmincreatememberrole"></a>`memberRole` | [`AdminMemberRole`](#adminmemberrole) | Member role. | + +### `Mutation.memberRoleAdminUpdate` + +{{< details >}} +**Introduced** in GitLab 17.10. +**Status**: Experiment. +{{< /details >}} + +Input type: `MemberRoleAdminUpdateInput` + +#### Arguments + +| Name | Type | Description | +| ---- | ---- | ----------- | +| <a id="mutationmemberroleadminupdateclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. | +| <a id="mutationmemberroleadminupdatedescription"></a>`description` | [`String`](#string) | Description of the member role. | +| <a id="mutationmemberroleadminupdateid"></a>`id` | [`MemberRoleID!`](#memberroleid) | ID of the member role to mutate. | +| <a id="mutationmemberroleadminupdatename"></a>`name` | [`String`](#string) | Name of the member role. | +| <a id="mutationmemberroleadminupdatepermissions"></a>`permissions` | [`[MemberRoleAdminPermission!]`](#memberroleadminpermission) | List of all customizable admin permissions. | + +#### Fields + +| Name | Type | Description | +| ---- | ---- | ----------- | +| <a id="mutationmemberroleadminupdateclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. | +| <a id="mutationmemberroleadminupdateerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. | +| <a id="mutationmemberroleadminupdatememberrole"></a>`memberRole` | [`AdminMemberRole`](#adminmemberrole) | Member role. | ### `Mutation.memberRoleCreate` @@ -7680,7 +7707,7 @@ Input type: `MemberRoleCreateInput` | ---- | ---- | ----------- | | <a id="mutationmemberrolecreateclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. | | <a id="mutationmemberrolecreateerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. | -| <a id="mutationmemberrolecreatememberrole"></a>`memberRole` | [`MemberRole`](#memberrole) | Updated member role. | +| <a id="mutationmemberrolecreatememberrole"></a>`memberRole` | [`MemberRole`](#memberrole) | Member role. | ### `Mutation.memberRoleDelete` @@ -7751,7 +7778,7 @@ Input type: `MemberRoleUpdateInput` | ---- | ---- | ----------- | | <a id="mutationmemberroleupdateclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. | | <a id="mutationmemberroleupdateerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. | -| <a id="mutationmemberroleupdatememberrole"></a>`memberRole` | [`MemberRole`](#memberrole) | Updated member role. | +| <a id="mutationmemberroleupdatememberrole"></a>`memberRole` | [`MemberRole`](#memberrole) | Member role. | ### `Mutation.mergeRequestAccept` diff --git a/ee/app/graphql/ee/types/mutation_type.rb b/ee/app/graphql/ee/types/mutation_type.rb index 3b18eeae4faf50c5721b75a9e5b081a9c97fa258..32d5b2e4f79dd8101d435fe50dc73666e1a5c1a4 100644 --- a/ee/app/graphql/ee/types/mutation_type.rb +++ b/ee/app/graphql/ee/types/mutation_type.rb @@ -57,7 +57,8 @@ def self.authorization_scopes mount_mutation ::Mutations::Iterations::Cadences::Destroy mount_mutation ::Mutations::MemberRoles::Update mount_mutation ::Mutations::MemberRoles::Create, experiment: { milestone: '16.5' } - mount_mutation ::Mutations::MemberRoles::CreateAdmin, experiment: { milestone: '17.7' } + mount_mutation ::Mutations::MemberRoles::Admin::Create, experiment: { milestone: '17.7' } + mount_mutation ::Mutations::MemberRoles::Admin::Update, experiment: { milestone: '17.10' } mount_mutation ::Mutations::MemberRoles::Delete, experiment: { milestone: '16.7' } mount_mutation ::Mutations::RequirementsManagement::CreateRequirement mount_mutation ::Mutations::RequirementsManagement::ExportRequirements diff --git a/ee/app/graphql/mutations/member_roles/admin/base.rb b/ee/app/graphql/mutations/member_roles/admin/base.rb new file mode 100644 index 0000000000000000000000000000000000000000..8ecc7d0bf6c4a1021137e5c2e04358e7baf32538 --- /dev/null +++ b/ee/app/graphql/mutations/member_roles/admin/base.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +module Mutations + module MemberRoles + module Admin + # rubocop:disable GraphQL/GraphqlName -- This is a base mutation so name is not needed here + class Base < ::Mutations::MemberRoles::Base + argument :permissions, + [Types::Members::CustomizableAdminPermissionsEnum], + required: false, + description: 'List of all customizable admin permissions.' + + field :member_role, + ::Types::Members::AdminMemberRoleType, + description: 'Member role.', + null: true + + def ready?(**args) + if gitlab_com_subscription? + raise Gitlab::Graphql::Errors::ArgumentError, 'admin member roles are not available on SaaS instance.' + end + + raise_resource_not_available_error! unless Feature.enabled?(:custom_admin_roles, :instance) + + super + end + end + # rubocop:enable GraphQL/GraphqlName + end + end +end diff --git a/ee/app/graphql/mutations/member_roles/admin/create.rb b/ee/app/graphql/mutations/member_roles/admin/create.rb new file mode 100644 index 0000000000000000000000000000000000000000..8d2c7f9374ef760d0e898f93cf1e6b0506ed4ad1 --- /dev/null +++ b/ee/app/graphql/mutations/member_roles/admin/create.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +module Mutations + module MemberRoles + module Admin + class Create < Base + graphql_name 'MemberRoleAdminCreate' + + authorize :admin_member_role + + def resolve(**args) + params = canonicalize_for_create(args) + response = ::MemberRoles::CreateService.new(current_user, params).execute + + raise_resource_not_available_error! if response.error? && response.reason == :unauthorized + + { + member_role: response.payload[:member_role], + errors: response.errors + } + end + end + end + end +end diff --git a/ee/app/graphql/mutations/member_roles/admin/update.rb b/ee/app/graphql/mutations/member_roles/admin/update.rb new file mode 100644 index 0000000000000000000000000000000000000000..8120750200d5e6b8b23dd7c641b3bb3284c1a969 --- /dev/null +++ b/ee/app/graphql/mutations/member_roles/admin/update.rb @@ -0,0 +1,43 @@ +# frozen_string_literal: true + +module Mutations + module MemberRoles + module Admin + class Update < Base + graphql_name 'MemberRoleAdminUpdate' + + authorize :admin_member_role + + argument :id, ::Types::GlobalIDType[::MemberRole], + required: true, + description: 'ID of the member role to mutate.' + + def ready?(**args) + if args.except(:id).blank? + raise Gitlab::Graphql::Errors::ArgumentError, 'The list of member_role attributes is empty' + end + + super + end + + def resolve(**args) + member_role = authorized_find!(id: args.delete(:id)) + + unless member_role.admin_related_role? + raise Gitlab::Graphql::Errors::ArgumentError, 'This mutation can only be used to update admin member roles' + end + + params = canonicalize_for_update(args, + available_permissions: MemberRole.all_customizable_admin_permission_keys) + + response = ::MemberRoles::UpdateService.new(current_user, params).execute(member_role) + + { + member_role: response.payload[:member_role], + errors: response.errors + } + end + end + end + end +end diff --git a/ee/app/graphql/mutations/member_roles/base.rb b/ee/app/graphql/mutations/member_roles/base.rb index cda54d8c0e4288ead4b64da41a33f95c480e2c20..c1a1772a99ef9a00a2f998aca3857c83b47871d3 100644 --- a/ee/app/graphql/mutations/member_roles/base.rb +++ b/ee/app/graphql/mutations/member_roles/base.rb @@ -3,23 +3,47 @@ module Mutations module MemberRoles class Base < ::Mutations::BaseMutation - authorize :admin_member_role + include ::GitlabSubscriptions::SubscriptionHelper - field :member_role, ::Types::MemberRoles::MemberRoleType, - description: 'Updated member role.', null: true + field :member_role, + ::Types::MemberRoles::MemberRoleType, + description: 'Member role.', + null: true argument :description, GraphQL::Types::String, required: false, description: 'Description of the member role.' + argument :name, GraphQL::Types::String, required: false, description: 'Name of the member role.' + argument :permissions, [Types::MemberRoles::PermissionsEnum], required: false, description: 'List of all customizable permissions.' + + private + + def canonicalize_for_create(args) + permissions = args.delete(:permissions) || [] + permissions.each_with_object(args) do |permission, new_args| + new_args[permission.downcase] = true + end + end + + def canonicalize_for_update(args, available_permissions: MemberRole.all_customizable_standard_permissions.keys) + permissions = args.delete(:permissions) || [] + permissions.each_with_object(args) do |permission, new_args| + new_args[permission.downcase] = true + end + + (available_permissions - permissions).each_with_object(args) do |permission, new_args| + new_args[permission.downcase] = false + end + end end end end diff --git a/ee/app/graphql/mutations/member_roles/create.rb b/ee/app/graphql/mutations/member_roles/create.rb index fcc6bfb5452da4de12864157f3b3aaa79a3c283a..c41b5b8cd437b99f247caf07f1d696146df7ba8a 100644 --- a/ee/app/graphql/mutations/member_roles/create.rb +++ b/ee/app/graphql/mutations/member_roles/create.rb @@ -5,9 +5,10 @@ module MemberRoles class Create < Base graphql_name 'MemberRoleCreate' - include ::GitlabSubscriptions::SubscriptionHelper include Mutations::ResolvesNamespace + authorize :admin_member_role + argument :base_access_level, ::Types::Members::MemberRoles::AccessLevelEnum, required: true, @@ -30,7 +31,7 @@ def ready?(**args) def resolve(**args) group = find_group(args.delete(:group_path)) - params = canonicalize(args.merge(namespace: group)) + params = canonicalize_for_create(args.merge(namespace: group)) response = ::MemberRoles::CreateService.new(current_user, params).execute raise_resource_not_available_error! if response.error? && response.reason == :unauthorized @@ -68,13 +69,6 @@ def extra_group_path?(args) args[:group_path].present? end - - def canonicalize(args) - permissions = args.delete(:permissions) || [] - permissions.each_with_object(args) do |permission, new_args| - new_args[permission.downcase] = true - end - end end end end diff --git a/ee/app/graphql/mutations/member_roles/create_admin.rb b/ee/app/graphql/mutations/member_roles/create_admin.rb deleted file mode 100644 index bcf00df594e0a95f349efc47567dcd031a0f8f24..0000000000000000000000000000000000000000 --- a/ee/app/graphql/mutations/member_roles/create_admin.rb +++ /dev/null @@ -1,49 +0,0 @@ -# frozen_string_literal: true - -module Mutations - module MemberRoles - class CreateAdmin < Base - graphql_name 'MemberRoleAdminCreate' - - include ::GitlabSubscriptions::SubscriptionHelper - - argument :permissions, - [Types::Members::CustomizableAdminPermissionsEnum], - required: true, - description: 'List of all customizable admin permissions.' - - field :member_role, ::Types::Members::AdminMemberRoleType, - description: 'Created member role.', null: true - - def ready?(**args) - if gitlab_com_subscription? - raise Gitlab::Graphql::Errors::ArgumentError, 'admin member roles are not available on SaaS instance.' - end - - raise_resource_not_available_error! unless Feature.enabled?(:custom_ability_read_admin_dashboard, current_user) - - super - end - - def resolve(**args) - response = ::MemberRoles::CreateService.new(current_user, canonicalize(args)).execute - - raise_resource_not_available_error! if response.error? && response.reason == :unauthorized - - { - member_role: response.payload[:member_role], - errors: response.errors - } - end - - private - - def canonicalize(args) - permissions = args.delete(:permissions) || [] - permissions.each_with_object(args) do |permission, new_args| - new_args[permission.downcase] = true - end - end - end - end -end diff --git a/ee/app/graphql/mutations/member_roles/update.rb b/ee/app/graphql/mutations/member_roles/update.rb index 4541c16c7f93a8721837acb9500d5cd661780700..0b990fedb2e7b418c3c4314b59068d190b473239 100644 --- a/ee/app/graphql/mutations/member_roles/update.rb +++ b/ee/app/graphql/mutations/member_roles/update.rb @@ -5,6 +5,8 @@ module MemberRoles class Update < Base graphql_name 'MemberRoleUpdate' + authorize :admin_member_role + argument :id, ::Types::GlobalIDType[::MemberRole], required: true, description: 'ID of the member role to mutate.' @@ -20,7 +22,7 @@ def ready?(**args) def resolve(**args) member_role = authorized_find!(id: args.delete(:id)) - params = canonicalize(args) + params = canonicalize_for_update(args) response = ::MemberRoles::UpdateService.new(current_user, params).execute(member_role) { @@ -28,24 +30,6 @@ def resolve(**args) errors: response.errors } end - - private - - def canonicalize(args) - permissions = args.delete(:permissions) - return args if permissions.nil? - - available_permissions = MemberRole.all_customizable_permissions.keys - - set_permissions(args, permissions & available_permissions, true) - set_permissions(args, available_permissions - permissions, false) - end - - def set_permissions(args, permissions, value) - permissions.each_with_object(args) do |permission, new_args| - new_args[permission] = value - end - end end end end diff --git a/ee/app/graphql/mutations/users/member_roles/assign.rb b/ee/app/graphql/mutations/users/member_roles/assign.rb index 8813c219b1c147629655a461418213bba66ded23..49308a759ce316b459583019bdc204530c8e1bd5 100644 --- a/ee/app/graphql/mutations/users/member_roles/assign.rb +++ b/ee/app/graphql/mutations/users/member_roles/assign.rb @@ -25,8 +25,7 @@ class Assign < BaseMutation def ready?(**args) raise_resource_not_available_error! if gitlab_com_subscription? - raise_resource_not_available_error! unless Feature.enabled?(:custom_ability_read_admin_dashboard, - current_user) + raise_resource_not_available_error! unless Feature.enabled?(:custom_admin_roles, :instance) raise_resource_not_available_error! unless current_user.can?(:admin_member_role) diff --git a/ee/app/models/members/member_role.rb b/ee/app/models/members/member_role.rb index 8fe9211bbd05f6f03cc2d8e58a1cacf2d6f31fef..7c8e392c0c8aab8ae0aa45c1b3922cf346fc9e81 100644 --- a/ee/app/models/members/member_role.rb +++ b/ee/app/models/members/member_role.rb @@ -119,7 +119,8 @@ def customizable_permissions_exempt_from_consuming_seat end def permission_enabled?(permission, user = nil) - if ::Feature.disabled?(:custom_admin_roles, user) && all_customizable_admin_permission_keys.include?(permission) + if ::Feature.disabled?(:custom_admin_roles, :instance) && + all_customizable_admin_permission_keys.include?(permission) return false end diff --git a/ee/app/services/users/member_roles/assign_service.rb b/ee/app/services/users/member_roles/assign_service.rb index c80165b13ee7bfb2b089770b8b90253dffe5707a..d16593b90dcae9c2fb49031b2d71ae83aa462850 100644 --- a/ee/app/services/users/member_roles/assign_service.rb +++ b/ee/app/services/users/member_roles/assign_service.rb @@ -22,7 +22,7 @@ def execute ) end - unless Feature.enabled?(:custom_ability_read_admin_dashboard, current_user) + unless Feature.enabled?(:custom_admin_roles, :instance) return ServiceResponse.error(message: 'Not yet available', reason: :forbidden) end diff --git a/ee/spec/requests/api/graphql/mutations/member_role/create_admin_member_role_spec.rb b/ee/spec/requests/api/graphql/mutations/member_roles/admin/create_spec.rb similarity index 84% rename from ee/spec/requests/api/graphql/mutations/member_role/create_admin_member_role_spec.rb rename to ee/spec/requests/api/graphql/mutations/member_roles/admin/create_spec.rb index 70e5e8fc1f97cbcf1eaa914ec8e9f850cbdfffe6..0a3e3f1b90ad8bff5e1d8784320304482e5db6df 100644 --- a/ee/spec/requests/api/graphql/mutations/member_role/create_admin_member_role_spec.rb +++ b/ee/spec/requests/api/graphql/mutations/member_roles/admin/create_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe 'creating member role', feature_category: :permissions do +RSpec.describe 'creating admin member role', :enable_admin_mode, feature_category: :permissions do include GraphqlHelpers let_it_be_with_reload(:current_user) { create(:admin) } @@ -33,7 +33,7 @@ subject(:create_member_role) { graphql_mutation_response(:member_role_admin_create) } - context 'without the custom roles feature', :enable_admin_mode do + context 'without the custom roles feature' do before do stub_licensed_features(custom_roles: false) end @@ -41,7 +41,7 @@ it_behaves_like 'a mutation that returns a top-level access error' end - context 'with the custom roles feature', :enable_admin_mode do + context 'with the custom roles feature' do before do stub_licensed_features(custom_roles: true) end @@ -58,9 +58,9 @@ context 'when on self-managed' do it_behaves_like 'a mutation that creates a member role' - context 'when custom_ability_read_admin_dashboard FF is disabled' do + context 'when custom_admin_roles FF is disabled' do before do - stub_feature_flags(custom_ability_read_admin_dashboard: false) + stub_feature_flags(custom_admin_roles: false) end it_behaves_like 'a mutation that returns a top-level access error', diff --git a/ee/spec/requests/api/graphql/mutations/member_roles/admin/update_spec.rb b/ee/spec/requests/api/graphql/mutations/member_roles/admin/update_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..9e33a4da7cdae625972fd390aa50c8f65b0b28a1 --- /dev/null +++ b/ee/spec/requests/api/graphql/mutations/member_roles/admin/update_spec.rb @@ -0,0 +1,119 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'updating admin member role', :enable_admin_mode, feature_category: :permissions do + include GraphqlHelpers + + let_it_be(:member_role) { create(:member_role, :read_admin_dashboard) } + let_it_be_with_reload(:current_user) { create(:admin) } + + let(:name) { 'new name' } + let(:description) { 'new description' } + let(:permissions) { %w[READ_ADMIN_MONITORING READ_ADMIN_CICD] } + + let(:input) do + { 'id' => member_role.to_global_id.to_s, 'name' => name, 'description' => description, + 'permissions' => permissions } + end + + let(:fields) do + <<~FIELDS + errors + memberRole { + id + name + description + enabledPermissions { + nodes { + value + } + } + } + FIELDS + end + + let(:mutation) { graphql_mutation(:member_role_admin_update, input, fields) } + + subject(:update_admin_member_role) { graphql_mutation_response(:member_role_admin_update) } + + context 'without the custom roles feature' do + before do + stub_licensed_features(custom_roles: false) + end + + it_behaves_like 'a mutation that returns a top-level access error' + end + + context 'with the custom roles feature' do + before do + stub_licensed_features(custom_roles: true) + end + + context 'when on SaaS' do + before do + stub_saas_features(gitlab_com_subscriptions: true) + end + + it_behaves_like 'a mutation that returns top-level errors', + errors: ['admin member roles are not available on SaaS instance.'] + end + + context 'when on self-managed' do + it 'returns success' do + post_graphql_mutation(mutation, current_user: current_user) + + expect(graphql_errors).to be_nil + + expect(update_admin_member_role['memberRole']).to include('name' => 'new name') + + expect(update_admin_member_role['memberRole']).to include('description' => 'new description') + + expect(update_admin_member_role['memberRole']['enabledPermissions']['nodes'].flat_map(&:values)) + .to match_array(permissions) + end + + it 'updates the member role' do + post_graphql_mutation(mutation, current_user: current_user) + + member_role.reload + + expect(member_role.name).to eq('new name') + expect(member_role.description).to eq('new description') + expect(member_role.read_admin_monitoring).to be(true) + expect(member_role.read_admin_cicd).to be(true) + expect(member_role.read_admin_dashboard).to be(false) + end + + context 'when member role is not an admin role' do + let(:member_role) { create(:member_role, :guest, :read_code, :instance) } + + it_behaves_like 'a mutation that returns top-level errors', + errors: ['This mutation can only be used to update admin member roles'] + end + + context 'when `custom_admin_roles` feature-flag is disabled' do + before do + stub_feature_flags(custom_admin_roles: false) + end + + it_behaves_like 'a mutation that returns a top-level access error' + end + + context 'when current user is not an admin' do + before do + current_user.update!(admin: false) + end + + it_behaves_like 'a mutation that returns a top-level access error' + end + + context 'with missing arguments' do + let(:input) { { 'id' => member_role.to_global_id.to_s } } + + it_behaves_like 'a mutation that returns top-level errors', + errors: ['The list of member_role attributes is empty'] + end + end + end +end diff --git a/ee/spec/requests/api/graphql/mutations/member_role/create_member_role_spec.rb b/ee/spec/requests/api/graphql/mutations/member_roles/create_spec.rb similarity index 96% rename from ee/spec/requests/api/graphql/mutations/member_role/create_member_role_spec.rb rename to ee/spec/requests/api/graphql/mutations/member_roles/create_spec.rb index 496ff21b0485fe3275a71a60099c2b2ab90836af..ea2ebebc800ba9d2e203e034a21d9fc8d303d5c5 100644 --- a/ee/spec/requests/api/graphql/mutations/member_role/create_member_role_spec.rb +++ b/ee/spec/requests/api/graphql/mutations/member_roles/create_spec.rb @@ -99,7 +99,7 @@ it_behaves_like 'a mutation that returns top-level errors', errors: ["The resource that you are attempting to access does not exist or " \ - "you don't have permission to perform this action"] + "you don't have permission to perform this action"] end context 'with missing arguments' do @@ -123,7 +123,7 @@ context 'when the current user is not an instance admin' do it_behaves_like 'a mutation that returns a top-level access error', errors: ["The resource that you are attempting to access does not exist or " \ - "you don't have permission to perform this action"] + "you don't have permission to perform this action"] end context 'when the current user is an instance admin' do diff --git a/ee/spec/requests/api/graphql/mutations/member_role/delete_member_role_spec.rb b/ee/spec/requests/api/graphql/mutations/member_roles/delete_spec.rb similarity index 100% rename from ee/spec/requests/api/graphql/mutations/member_role/delete_member_role_spec.rb rename to ee/spec/requests/api/graphql/mutations/member_roles/delete_spec.rb diff --git a/ee/spec/requests/api/graphql/mutations/member_role/update_member_role_spec.rb b/ee/spec/requests/api/graphql/mutations/member_roles/update_spec.rb similarity index 62% rename from ee/spec/requests/api/graphql/mutations/member_role/update_member_role_spec.rb rename to ee/spec/requests/api/graphql/mutations/member_roles/update_spec.rb index d25354cd133e90fa35f6d222c291907928887a09..15c04422f1eced49cfa65a5c80dd5540bf45ce4f 100644 --- a/ee/spec/requests/api/graphql/mutations/member_role/update_member_role_spec.rb +++ b/ee/spec/requests/api/graphql/mutations/member_roles/update_spec.rb @@ -6,13 +6,14 @@ include GraphqlHelpers let_it_be(:group) { create(:group) } - let_it_be(:member_role) { create(:member_role, namespace: group) } + let_it_be(:member_role) { create(:member_role, :read_code, namespace: group) } let_it_be(:current_user) { create(:user) } let(:name) { 'new name' } - let(:permissions) { MemberRole.all_customizable_standard_permissions.keys.map(&:to_s).map(&:upcase) } + let(:description) { 'new description' } + let(:permissions) { %w[READ_VULNERABILITY ADMIN_VULNERABILITY] } - let(:input) { { 'name' => name, 'permissions' => permissions } } + let(:input) { { 'name' => name, 'description' => description, 'permissions' => permissions } } let(:mutation) { graphql_mutation(:memberRoleUpdate, input.merge('id' => member_role.to_global_id.to_s), fields) } let(:fields) do <<~FIELDS @@ -72,14 +73,22 @@ expect(update_member_role['memberRole']).to include('name' => 'new name') + expect(update_member_role['memberRole']).to include('description' => 'new description') + expect(update_member_role['memberRole']['enabledPermissions']['nodes'].flat_map(&:values)) .to match_array(permissions) end it 'updates the member role' do - expect { post_graphql_mutation(mutation, current_user: current_user) } - .to change { member_role.reload.name }.to('new name') - .and change { member_role.read_vulnerability }.to(true) + post_graphql_mutation(mutation, current_user: current_user) + + member_role.reload + + expect(member_role.name).to eq('new name') + expect(member_role.description).to eq('new description') + expect(member_role.read_vulnerability).to be(true) + expect(member_role.admin_vulnerability).to be(true) + expect(member_role.read_code).to be(false) end end @@ -105,6 +114,31 @@ .to include("The list of member_role attributes is empty") end end + + context 'when ability is disabled' do + before do + stub_feature_flag_definition("custom_ability_admin_vulnerability") + stub_feature_flags(custom_ability_admin_vulnerability: false) + end + + it 'returns success without the ability' do + post_graphql_mutation(mutation, current_user: current_user) + + expect(graphql_errors).to be_nil + + expect(update_member_role['memberRole']['enabledPermissions']['nodes'].flat_map(&:values)) + .to eq(['READ_VULNERABILITY']) + end + + it 'updates member role' do + post_graphql_mutation(mutation, current_user: current_user) + + member_role.reload + + expect(member_role.read_vulnerability).to be(true) + expect(member_role.admin_vulnerability).to be(true) + end + end end end end diff --git a/ee/spec/requests/api/graphql/mutations/users/member_roles/assign_spec.rb b/ee/spec/requests/api/graphql/mutations/users/member_roles/assign_spec.rb index feeb1ddfa9dff8aa6fb5c059e1e2eaf61319823a..8c689249f884a78dbe3e1c46e97f2493c48d4937 100644 --- a/ee/spec/requests/api/graphql/mutations/users/member_roles/assign_spec.rb +++ b/ee/spec/requests/api/graphql/mutations/users/member_roles/assign_spec.rb @@ -61,9 +61,9 @@ def mutation_response end context 'when current user is an admin', :enable_admin_mode do - context 'when custom_ability_read_admin_dashboard FF is disabled' do + context 'when custom_admin_roles FF is disabled' do before do - stub_feature_flags(custom_ability_read_admin_dashboard: false) + stub_feature_flags(custom_admin_roles: false) end it_behaves_like 'a mutation that returns a top-level access error', @@ -71,7 +71,7 @@ def mutation_response "you don't have permission to perform this action"] end - context 'when custom_ability_read_admin_dashboard FF is enabled' do + context 'when custom_admin_roles FF is enabled' do context 'when on SaaS' do before do stub_saas_features(gitlab_com_subscriptions: true) diff --git a/ee/spec/services/users/member_roles/assign_service_spec.rb b/ee/spec/services/users/member_roles/assign_service_spec.rb index f101465fedbf1b89587024d3e55ac573ee4befc9..2db4078e8fce4fa8032ef6787a6b9576ee32ee23 100644 --- a/ee/spec/services/users/member_roles/assign_service_spec.rb +++ b/ee/spec/services/users/member_roles/assign_service_spec.rb @@ -28,9 +28,9 @@ end context 'when current user is an admin', :enable_admin_mode do - context 'when custom_ability_read_admin_dashboard FF is disabled' do + context 'when custom_admin_roles FF is disabled' do before do - stub_feature_flags(custom_ability_read_admin_dashboard: false) + stub_feature_flags(custom_admin_roles: false) end it 'returns an error' do @@ -38,7 +38,7 @@ end end - context 'when custom_ability_read_admin_dashboard FF is enabled' do + context 'when custom_admin_roles FF is enabled' do context 'when member_role param is present' do it 'creates a new user member role relation' do expect { assign_member_role }.to change { Users::UserMemberRole.count }.by(1)