diff --git a/app/views/admin/groups/_group.html.haml b/app/views/admin/groups/_group.html.haml index 8743d87b6776355a078f5b78db32ea5d3b712362..0aca7d3fefbdce43433e663e74db96b2d3370ef3 100644 --- a/app/views/admin/groups/_group.html.haml +++ b/app/views/admin/groups/_group.html.haml @@ -30,9 +30,10 @@ %span.gl-ml-5.visibility-icon.has-tooltip{ data: { container: 'body', placement: 'left' }, title: visibility_icon_description(group) } = visibility_level_icon(group.visibility_level) - .controls.gl-flex.gl-shrink-0.gl-ml-5 - = render Pajamas::ButtonComponent.new(href: admin_group_edit_path(group), button_options: { id: "edit_#{dom_id(group)}" }) do - = _('Edit') + - if current_user.can_admin_all_resources? + .controls.gl-flex.gl-shrink-0.gl-ml-5 + = render Pajamas::ButtonComponent.new(href: admin_group_edit_path(group), button_options: { id: "edit_#{dom_id(group)}" }) do + = _('Edit') - = form_tag([:admin, group], method: :delete, id: remove_form_id) do - .js-confirm-danger{ data: group_confirm_modal_data(group: group, remove_form_id: remove_form_id, permanently_remove: true, button_text: _('Delete')) } + = form_tag([:admin, group], method: :delete, id: remove_form_id) do + .js-confirm-danger{ data: group_confirm_modal_data(group: group, remove_form_id: remove_form_id, permanently_remove: true, button_text: _('Delete')) } diff --git a/app/views/admin/groups/index.html.haml b/app/views/admin/groups/index.html.haml index b297a48144d83b969c2f017179e31f375f40f504..5f84f4bc6efa54689b6e994703cb8e69fbae924e 100644 --- a/app/views/admin/groups/index.html.haml +++ b/app/views/admin/groups/index.html.haml @@ -3,8 +3,9 @@ = render ::Layouts::PageHeadingComponent.new(_('Groups'), options: { data: { event_tracking_load: 'true', event_tracking: 'view_admin_groups_pageload' } }) do |c| - c.with_actions do - = link_button_to new_admin_group_path, variant: :confirm do - = _('New group') + - if current_user.can_admin_all_resources? + = link_button_to new_admin_group_path, variant: :confirm do + = _('New group') - if Feature.enabled?(:admin_groups_vue, current_user) #js-admin-groups-app diff --git a/app/views/admin/groups/show.html.haml b/app/views/admin/groups/show.html.haml index ac7cf6344c6b16fd76f7eaf3f2138227d89cc55a..b3a26c036cd45b9f52bb26909be9b72dd5b0f7f8 100644 --- a/app/views/admin/groups/show.html.haml +++ b/app/views/admin/groups/show.html.haml @@ -7,9 +7,10 @@ = render ::Layouts::PageHeadingComponent.new(@group.full_name) do |c| - c.with_actions do - = render Pajamas::ButtonComponent.new(href: admin_group_edit_path(@group), - button_options: { data: { testid: 'edit-group-link' }}) do - = _('Edit') + - if current_user.can_admin_all_resources? + = render Pajamas::ButtonComponent.new(href: admin_group_edit_path(@group), + button_options: { data: { testid: 'edit-group-link' }}) do + = _('Edit') .gl-grid.md:gl-grid-cols-2.gl-gap-5 .gl-flex.gl-flex-col.gl-gap-5 diff --git a/app/views/admin/projects/index.html.haml b/app/views/admin/projects/index.html.haml index 610831a44a760da17445fccb422ad4333b0c8b5c..55c7b2b6f82afacc384bd2be8224a1b2724ac85d 100644 --- a/app/views/admin/projects/index.html.haml +++ b/app/views/admin/projects/index.html.haml @@ -9,8 +9,9 @@ = render ::Layouts::PageHeadingComponent.new(_('Projects'), options: { data: { event_tracking_load: 'true', event_tracking: 'view_admin_projects_pageload' } }) do |c| - c.with_actions do - = link_button_to new_project_path, variant: :confirm do - = _('New Project') + - if current_user.can_admin_all_resources? + = link_button_to new_project_path, variant: :confirm do + = _('New Project') - if Feature.enabled?(:admin_projects_vue, current_user) #js-admin-projects-app{ data: { app_data: admin_projects_app_data } } diff --git a/ee/app/controllers/ee/admin/groups_controller.rb b/ee/app/controllers/ee/admin/groups_controller.rb index ebf75fac3d1a4c3346dd7d6c753822f126858916..820099c579ee0406009becaa84a7901b03da967f 100644 --- a/ee/app/controllers/ee/admin/groups_controller.rb +++ b/ee/app/controllers/ee/admin/groups_controller.rb @@ -10,6 +10,8 @@ module GroupsController prepended do feature_category :continuous_integration, [:reset_runners_minutes] + authorize! :read_admin_groups, only: %i[index show] + before_action do push_saas_feature(:gitlab_com_subscriptions) end diff --git a/ee/app/controllers/ee/admin/projects_controller.rb b/ee/app/controllers/ee/admin/projects_controller.rb index 51372efb037b15fdd86dc4bcc3c0b0a689e09a38..6c3895dbe6660a06c81f55068fb0696ad73152e5 100644 --- a/ee/app/controllers/ee/admin/projects_controller.rb +++ b/ee/app/controllers/ee/admin/projects_controller.rb @@ -6,6 +6,8 @@ module ProjectsController extend ActiveSupport::Concern prepended do + authorize! :read_admin_projects, only: %i[index show] + before_action :limited_actions_message!, only: :show end end diff --git a/ee/spec/features/admin/admin_groups_spec.rb b/ee/spec/features/admin/admin_groups_spec.rb index 1432f2f56c6d0581b31a3a0ebf8971f42e56f231..d6faeedb4342117b48375c9e54beb093249780a5 100644 --- a/ee/spec/features/admin/admin_groups_spec.rb +++ b/ee/spec/features/admin/admin_groups_spec.rb @@ -2,57 +2,98 @@ require 'spec_helper' -RSpec.describe 'Admin Groups', feature_category: :hosted_runners do - include ::Ci::MinutesHelpers - +RSpec.describe 'Admin Groups', feature_category: :groups_and_projects do let_it_be(:group) { create :group } - let_it_be(:admin) { create(:admin) } - let_it_be(:project, reload: true) { create(:project, namespace: group) } - before do - sign_in(admin) - enable_admin_mode!(admin) - end + context 'when current user is an admin', feature_category: :hosted_runners do + include ::Ci::MinutesHelpers - describe 'show a group' do - context 'with compute usage' do - before do - project.update!(shared_runners_enabled: true) - set_ci_minutes_used(group, 300) - group.update!(shared_runners_minutes_limit: 400) - end + let_it_be(:admin) { create(:admin) } + let_it_be(:project, reload: true) { create(:project, namespace: group) } - context 'when gitlab saas', :saas do - it 'renders compute usage report' do - visit admin_group_path(group) + before do + sign_in(admin) + enable_admin_mode!(admin) + end - expect(page).to have_content('Compute quota: 300 / 400') + describe 'show a group' do + context 'with compute usage' do + before do + project.update!(shared_runners_enabled: true) + set_ci_minutes_used(group, 300) + group.update!(shared_runners_minutes_limit: 400) end - it 'renders additional compute minutes' do - group.update!(extra_shared_runners_minutes_limit: 100) + context 'when gitlab saas', :saas do + it 'renders compute usage report' do + visit admin_group_path(group) - visit admin_group_path(group) + expect(page).to have_content('Compute quota: 300 / 400') + end - expect(page).to have_content('Additional compute minutes:') - end - end + it 'renders additional compute minutes' do + group.update!(extra_shared_runners_minutes_limit: 100) - context 'when self-managed' do - it 'renders compute usage report' do - visit admin_group_path(group) + visit admin_group_path(group) - expect(page).not_to have_content('Compute quota: 300 / 400') + expect(page).to have_content('Additional compute minutes:') + end end - it 'does not render additional compute minutes' do - group.update!(extra_shared_runners_minutes_limit: 100) + context 'when self-managed' do + it 'renders compute usage report' do + visit admin_group_path(group) - visit admin_group_path(group) + expect(page).not_to have_content('Compute quota: 300 / 400') + end - expect(page).not_to have_content('Additional compute minutes:') + it 'does not render additional compute minutes' do + group.update!(extra_shared_runners_minutes_limit: 100) + + visit admin_group_path(group) + + expect(page).not_to have_content('Additional compute minutes:') + end end end end end + + context 'when current user is a regular user with read_admin_groups permission', :js do + let_it_be(:current_user) { create(:user) } + let_it_be(:role) { create(:admin_member_role, :read_admin_groups, user: current_user) } + + before do + stub_feature_flags(admin_groups_vue: false) + stub_licensed_features(custom_roles: true) + + enable_admin_mode!(current_user) + + sign_in(current_user) + end + + describe 'list' do + before do + stub_feature_flags(admin_groups_vue: false) + end + + it 'renders without admin-only buttons' do + visit admin_groups_path + + expect(page).to have_content(group.name) + expect(page).not_to have_content("New group") + expect(page).not_to have_content("Edit") + expect(page).not_to have_content("Delete") + end + end + + describe 'show', :aggregate_failures do + it 'shows the group without admin-only buttons' do + visit admin_group_path(group) + + expect(page).to have_content group.name + expect(page).not_to have_content("Edit") + end + end + end end diff --git a/ee/spec/features/admin/admin_projects_spec.rb b/ee/spec/features/admin/admin_projects_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..f1ed469c902a8e8ef7c2574eba709b4799935653 --- /dev/null +++ b/ee/spec/features/admin/admin_projects_spec.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'Admin Projects', feature_category: :permissions do + let_it_be_with_reload(:project) { create(:project) } + + context 'when user is a regular user with read_admin_projects custom admin role', :js do + let_it_be(:current_user) { create(:user) } + let_it_be(:role) { create(:admin_member_role, :read_admin_projects, user: current_user) } + + before do + stub_feature_flags(admin_projects_vue: false) + stub_licensed_features(custom_roles: true) + + enable_admin_mode!(current_user) + + sign_in(current_user) + end + + describe 'list' do + it 'renders without admin-only buttons' do + visit admin_projects_path + + expect(page).to have_content(project.name) + expect(page).not_to have_content("New Project") + expect(page).not_to have_content("Edit") + expect(page).not_to have_content("Delete") + end + end + + describe 'show', :aggregate_failures do + it 'shows the project without admin-only buttons' do + visit admin_project_path(project) + + expect(page).to have_content project.name + expect(page).not_to have_content("Edit") + end + end + end +end diff --git a/ee/spec/lib/ee/sidebars/admin/menus/admin_overview_menu_spec.rb b/ee/spec/lib/ee/sidebars/admin/menus/admin_overview_menu_spec.rb index c2f3932289d85457f1132a67b870c4df7333613d..26c3975592c06da331ef9e632f85708b59123b8a 100644 --- a/ee/spec/lib/ee/sidebars/admin/menus/admin_overview_menu_spec.rb +++ b/ee/spec/lib/ee/sidebars/admin/menus/admin_overview_menu_spec.rb @@ -51,8 +51,10 @@ subject(:menu_items) { menu.renderable_items.map(&:title) } where(:custom_ability, :expected_menu_items) do - :read_admin_users | [_('Dashboard'), _('Users')] - :read_admin_monitoring | [_('Dashboard'), _('Gitaly servers')] + :read_admin_users | [_('Dashboard'), _('Users')] + :read_admin_monitoring | [_('Dashboard'), _('Gitaly servers')] + :read_admin_groups | [_('Dashboard'), _('Groups')] + :read_admin_projects | [_('Dashboard'), _('Projects')] end with_them do diff --git a/ee/spec/requests/custom_roles/admin/read_admin_groups_spec.rb b/ee/spec/requests/custom_roles/admin/read_admin_groups_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..fb2495cee54f18457bf5c0ae65ecc15fecfec305 --- /dev/null +++ b/ee/spec/requests/custom_roles/admin/read_admin_groups_spec.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'User with read_admin_groups', :enable_admin_mode, feature_category: :permissions do + let_it_be(:current_user) { create(:user) } + let_it_be(:permission) { :read_admin_groups } + let_it_be(:role) { create(:admin_member_role, permission, user: current_user) } + + before do + stub_licensed_features(custom_roles: true) + sign_in(current_user) + end + + shared_examples 'is accessible' do + it 'is accessible' do + request + + expect(response).to have_gitlab_http_status(:ok) + end + end + + describe Admin::GroupsController do + describe "GET #index" do + subject(:request) { get admin_groups_path } + + it_behaves_like 'is accessible' + end + + describe "GET #show" do + subject(:request) { get admin_group_path(create(:group)) } + + it_behaves_like 'is accessible' + end + end +end diff --git a/ee/spec/requests/custom_roles/admin/read_admin_projects_spec.rb b/ee/spec/requests/custom_roles/admin/read_admin_projects_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..c9c4ef14cef3001b3c6142e6c00eb468d73306c0 --- /dev/null +++ b/ee/spec/requests/custom_roles/admin/read_admin_projects_spec.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'User with read_admin_projects', :enable_admin_mode, feature_category: :permissions do + let_it_be(:current_user) { create(:user) } + let_it_be(:permission) { :read_admin_projects } + let_it_be(:role) { create(:admin_member_role, permission, user: current_user) } + + before do + stub_licensed_features(custom_roles: true) + sign_in(current_user) + end + + shared_examples 'is accessible' do + it 'is accessible' do + request + + expect(response).to have_gitlab_http_status(:ok) + end + end + + describe Admin::ProjectsController do + describe "GET #index" do + subject(:request) { get admin_projects_path } + + it_behaves_like 'is accessible' + end + + describe "GET #show" do + subject(:request) { get admin_project_path(create(:project)) } + + it_behaves_like 'is accessible' + end + end +end diff --git a/ee/spec/views/admin/groups/_group.html.haml_spec.rb b/ee/spec/views/admin/groups/_group.html.haml_spec.rb index 1ecaa70819dd557008e7ad13bf70d754d77eeb56..993c1a98b0dfef5a87514a0bfeb6771fef40ef11 100644 --- a/ee/spec/views/admin/groups/_group.html.haml_spec.rb +++ b/ee/spec/views/admin/groups/_group.html.haml_spec.rb @@ -3,11 +3,13 @@ require 'spec_helper' RSpec.describe 'admin/groups/_group', feature_category: :system_access do + let_it_be(:user) { build(:admin) } let(:group) { build(:group) } before do assign(:group, group) allow(group).to receive(:storage_size) + allow(view).to receive(:current_user).and_return(user) end context 'for namespace plan badge' do diff --git a/lib/sidebars/admin/menus/admin_overview_menu.rb b/lib/sidebars/admin/menus/admin_overview_menu.rb index c58cff892e834f11329e89c1d385746e037f1e58..81f72e9de393492d19be16bb31f22f861b253d53 100644 --- a/lib/sidebars/admin/menus/admin_overview_menu.rb +++ b/lib/sidebars/admin/menus/admin_overview_menu.rb @@ -54,7 +54,7 @@ def projects_menu_item link: admin_projects_path, active_routes: { controller: 'admin/projects' }, item_id: :projects - ) { can?(current_user, :admin_all_resources) } + ) { can?(current_user, :read_admin_projects) } end def users_menu_item @@ -74,7 +74,7 @@ def groups_menu_item active_routes: { controller: 'groups' }, item_id: :groups, container_html_options: { 'data-testid': 'admin-overview-groups-link' } - ) { can?(current_user, :admin_all_resources) } + ) { can?(current_user, :read_admin_groups) } end def organizations_menu_item @@ -111,4 +111,4 @@ def gitaly_servers_menu_item end end -Sidebars::Admin::Menus::AdminOverviewMenu.prepend_mod_with('Sidebars::Admin::Menus::AdminOverviewMenu') +Sidebars::Admin::Menus::AdminOverviewMenu.prepend_mod