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