Commit 79b0e5dd authored by Tan Le's avatar Tan Le

Move audit events nav item and relax permission

This change moves `Audit Events` sub-menu in `Settings` menu within
Projects and Groups to `Security & Compliance`. We also relax the
permission to view this page from being only to administrator to
developer roles.
parent 0bfd480e
...@@ -21,7 +21,6 @@ module GroupsHelper ...@@ -21,7 +21,6 @@ module GroupsHelper
integrations#edit integrations#edit
ldap_group_links#index ldap_group_links#index
hooks#index hooks#index
audit_events#index
pipeline_quota#index pipeline_quota#index
] ]
end end
......
...@@ -437,8 +437,6 @@ ...@@ -437,8 +437,6 @@
%span %span
= _('Pages') = _('Pages')
= render_if_exists 'projects/sidebar/settings_audit_events'
= render 'shared/sidebar_toggle_button' = render 'shared/sidebar_toggle_button'
-# Shortcut to Project > Activity -# Shortcut to Project > Activity
......
...@@ -5,5 +5,20 @@ module AuditEvents ...@@ -5,5 +5,20 @@ module AuditEvents
def audit_logs_params def audit_logs_params
params.permit(:entity_type, :entity_id, :created_before, :created_after, :sort, :author_id) params.permit(:entity_type, :entity_id, :created_before, :created_after, :sort, :author_id)
end end
def audit_params
audit_logs_params
.then { |params| transform_author_entity_type(params) }
.then { |params| filter_by_author(params) }
end
# This is an interim change until we have proper API support within Audit Events
def transform_author_entity_type(params)
return params unless params[:entity_type] == 'Author'
params[:author_id] = params[:entity_id]
params.except(:entity_type, :entity_id)
end
end end
end end
...@@ -8,13 +8,10 @@ class Groups::AuditEventsController < Groups::ApplicationController ...@@ -8,13 +8,10 @@ class Groups::AuditEventsController < Groups::ApplicationController
include AuditEvents::DateRange include AuditEvents::DateRange
include Analytics::UniqueVisitsHelper include Analytics::UniqueVisitsHelper
before_action :authorize_admin_group!
before_action :check_audit_events_available! before_action :check_audit_events_available!
track_unique_visits :index, target_id: 'g_compliance_audit_events' track_unique_visits :index, target_id: 'g_compliance_audit_events'
layout 'group_settings'
feature_category :audit_events feature_category :audit_events
def index def index
...@@ -26,6 +23,11 @@ class Groups::AuditEventsController < Groups::ApplicationController ...@@ -26,6 +23,11 @@ class Groups::AuditEventsController < Groups::ApplicationController
private private
def check_audit_events_available!
render_404 unless can?(current_user, :read_group_audit_events, group) &&
group.feature_available?(:audit_events)
end
def events def events
strong_memoize(:events) do strong_memoize(:events) do
level = Gitlab::Audit::Levels::Group.new(group: group) level = Gitlab::Audit::Levels::Group.new(group: group)
...@@ -39,16 +41,7 @@ class Groups::AuditEventsController < Groups::ApplicationController ...@@ -39,16 +41,7 @@ class Groups::AuditEventsController < Groups::ApplicationController
end end
end end
def audit_params def filter_by_author(params)
# This is an interim change until we have proper API support within Audit Events can?(current_user, :admin_group, group) ? params : params.merge(author_id: current_user.id)
transform_author_entity_type(audit_logs_params)
end
def transform_author_entity_type(params)
return params unless params[:entity_type] == 'Author'
params[:author_id] = params[:entity_id]
params.except(:entity_type, :entity_id)
end end
end end
...@@ -8,11 +8,8 @@ class Projects::AuditEventsController < Projects::ApplicationController ...@@ -8,11 +8,8 @@ class Projects::AuditEventsController < Projects::ApplicationController
include AuditEvents::Sortable include AuditEvents::Sortable
include AuditEvents::DateRange include AuditEvents::DateRange
before_action :authorize_admin_project!
before_action :check_audit_events_available! before_action :check_audit_events_available!
layout 'project_settings'
feature_category :audit_events feature_category :audit_events
def index def index
...@@ -25,7 +22,8 @@ class Projects::AuditEventsController < Projects::ApplicationController ...@@ -25,7 +22,8 @@ class Projects::AuditEventsController < Projects::ApplicationController
private private
def check_audit_events_available! def check_audit_events_available!
render_404 unless @project.feature_available?(:audit_events) || LicenseHelper.show_promotions?(current_user) render_404 unless can?(current_user, :read_project_audit_events, project) &&
(project.feature_available?(:audit_events) || LicenseHelper.show_promotions?(current_user))
end end
def events def events
...@@ -41,16 +39,7 @@ class Projects::AuditEventsController < Projects::ApplicationController ...@@ -41,16 +39,7 @@ class Projects::AuditEventsController < Projects::ApplicationController
end end
end end
def audit_params def filter_by_author(params)
# This is an interim change until we have proper API support within Audit Events can?(current_user, :admin_project, project) ? params : params.merge(author_id: current_user.id)
transform_author_entity_type(audit_logs_params)
end
def transform_author_entity_type(params)
return params unless params[:entity_type] == 'Author'
params[:author_id] = params[:entity_id]
params.except(:entity_type, :entity_id)
end end
end end
...@@ -7,7 +7,6 @@ module EE ...@@ -7,7 +7,6 @@ module EE
override :sidebar_settings_paths override :sidebar_settings_paths
def sidebar_settings_paths def sidebar_settings_paths
super + %w[ super + %w[
audit_events#index
operations#show operations#show
] ]
end end
...@@ -177,6 +176,7 @@ module EE ...@@ -177,6 +176,7 @@ module EE
projects/threat_monitoring#show projects/threat_monitoring#show
projects/threat_monitoring#new projects/threat_monitoring#new
projects/threat_monitoring#edit projects/threat_monitoring#edit
projects/audit_events#index
] ]
end end
...@@ -279,6 +279,20 @@ module EE ...@@ -279,6 +279,20 @@ module EE
tabs.any? { |tab| project_nav_tab?(tab) } tabs.any? { |tab| project_nav_tab?(tab) }
end end
def top_level_link(project)
return project_security_dashboard_index_path(project) if project_nav_tab?(:security)
return project_audit_events_path(project) if project_nav_tab?(:audit_events)
project_dependencies_path(project)
end
def top_level_qa_selector(project)
return 'security_dashboard_link' if project_nav_tab?(:security)
return 'audit_events_settings_link' if project_nav_tab?(:audit_events)
'dependency_list_link'
end
def show_discover_project_security?(project) def show_discover_project_security?(project)
!!current_user && !!current_user &&
::Gitlab.com? && ::Gitlab.com? &&
...@@ -325,9 +339,18 @@ module EE ...@@ -325,9 +339,18 @@ module EE
nav_tabs << :threat_monitoring nav_tabs << :threat_monitoring
end end
if show_audit_events?(project)
nav_tabs << :audit_events
end
nav_tabs nav_tabs
end end
def show_audit_events?(project)
can?(current_user, :read_project_audit_events, project) &&
(project.feature_available?(:audit_events) || show_promotions?(current_user))
end
def remove_message_data(project) def remove_message_data(project)
{ {
project: project.path, project: project.path,
......
...@@ -27,9 +27,16 @@ module Groups::SecurityFeaturesHelper ...@@ -27,9 +27,16 @@ module Groups::SecurityFeaturesHelper
group_security_compliance_dashboard_path(group) group_security_compliance_dashboard_path(group)
elsif group_level_credentials_inventory_available?(group) elsif group_level_credentials_inventory_available?(group)
group_security_credentials_path(group) group_security_credentials_path(group)
elsif group_level_audit_events_available?(group)
group_audit_events_path(group)
end end
end end
def group_level_audit_events_available?(group)
group.feature_available?(:audit_events) &&
can?(current_user, :read_group_audit_events, group)
end
def group_level_security_dashboard_data(group) def group_level_security_dashboard_data(group)
{ {
projects_endpoint: expose_url(api_v4_groups_projects_path(id: group.id)), projects_endpoint: expose_url(api_v4_groups_projects_path(id: group.id)),
......
...@@ -24,12 +24,6 @@ ...@@ -24,12 +24,6 @@
%span %span
Webhooks Webhooks
- if @group.feature_available?(:audit_events)
= nav_link(path: 'audit_events#index') do
= link_to group_audit_events_path(@group), title: 'Audit Events', data: { qa_selector: 'audit_events_settings_link' } do
%span
Audit Events
- if show_usage_quotas_in_sidebar? && @group.parent.nil? && administration_nav_item_disabled - if show_usage_quotas_in_sidebar? && @group.parent.nil? && administration_nav_item_disabled
= nav_link(path: 'usage_quotas#index') do = nav_link(path: 'usage_quotas#index') do
= link_to group_usage_quotas_path(@group), title: s_('UsageQuota|Usage Quotas') do = link_to group_usage_quotas_path(@group), title: s_('UsageQuota|Usage Quotas') do
......
- main_path = primary_group_level_security_feature_path(@group) - main_path = primary_group_level_security_feature_path(@group)
- if main_path.present? - if main_path.present?
= nav_link(path: %w[dashboard#show vulnerabilities#index compliance_dashboards#show credentials#index]) do = nav_link(path: %w[dashboard#show vulnerabilities#index compliance_dashboards#show credentials#index audit_events#index]) do
= link_to main_path, data: { qa_selector: 'security_compliance_link' } do = link_to main_path, data: { qa_selector: 'security_compliance_link' } do
.nav-icon-container .nav-icon-container
= sprite_icon('shield') = sprite_icon('shield')
...@@ -27,6 +27,11 @@ ...@@ -27,6 +27,11 @@
= link_to group_security_credentials_path(@group), title: _('Credentials') do = link_to group_security_credentials_path(@group), title: _('Credentials') do
%span= _('Credentials') %span= _('Credentials')
- if group_level_audit_events_available?(@group)
= nav_link(path: 'audit_events#index') do
= link_to group_audit_events_path(@group), title: _('Audit Events'), data: { qa_selector: 'audit_events_settings_link' } do
%span= _('Audit Events')
- elsif show_discover_group_security?(@group) - elsif show_discover_group_security?(@group)
= nav_link(path: group_security_discover_path(@group)) do = nav_link(path: group_security_discover_path(@group)) do
= link_to group_security_discover_path(@group) do = link_to group_security_discover_path(@group) do
......
- if any_project_nav_tab?([:security, :dependencies, :licenses]) - if any_project_nav_tab?([:security, :dependencies, :licenses, :audit_events])
- top_level_link = project_nav_tab?(:security) ? project_security_dashboard_index_path(@project) : project_dependencies_path(@project)
- top_level_qa_selector = project_nav_tab?(:security) ? 'security_dashboard_link' : 'dependency_list_link'
= nav_link(path: sidebar_security_paths) do = nav_link(path: sidebar_security_paths) do
= link_to top_level_link, data: { qa_selector: top_level_qa_selector } do = link_to top_level_link(@project), data: { qa_selector: top_level_qa_selector(@project) } do
.nav-icon-container .nav-icon-container
= sprite_icon('shield') = sprite_icon('shield')
%span.nav-item-name %span.nav-item-name
...@@ -11,14 +8,14 @@ ...@@ -11,14 +8,14 @@
%ul.sidebar-sub-level-items %ul.sidebar-sub-level-items
= nav_link(path: sidebar_security_paths, html_options: { class: "fly-out-top-item" } ) do = nav_link(path: sidebar_security_paths, html_options: { class: "fly-out-top-item" } ) do
= link_to top_level_link do = link_to top_level_link(@project) do
%strong.fly-out-top-item-name %strong.fly-out-top-item-name
= _('Security & Compliance') = _('Security & Compliance')
%li.divider.fly-out-top-item %li.divider.fly-out-top-item
- if project_nav_tab?(:security) - if project_nav_tab?(:security)
= nav_link(path: 'projects/security/dashboard#index') do = nav_link(path: 'projects/security/dashboard#index') do
= link_to project_security_dashboard_index_path(@project), title: _('Security Dashboard') do = link_to project_security_dashboard_index_path(@project), title: _('Security Dashboard'), data: { qa_selector: 'security_dashboard_link' } do
%span= _('Security Dashboard') %span= _('Security Dashboard')
= nav_link(path: ['projects/security/vulnerability_report#index', 'projects/security/vulnerabilities#show']) do = nav_link(path: ['projects/security/vulnerability_report#index', 'projects/security/vulnerabilities#show']) do
...@@ -50,6 +47,11 @@ ...@@ -50,6 +47,11 @@
= link_to project_security_configuration_path(@project), title: _('Configuration'), data: { qa_selector: 'security_configuration_link'} do = link_to project_security_configuration_path(@project), title: _('Configuration'), data: { qa_selector: 'security_configuration_link'} do
%span= _('Configuration') %span= _('Configuration')
- if project_nav_tab?(:audit_events)
= nav_link(controller: :audit_events) do
= link_to project_audit_events_path(@project), title: _('Audit Events'), data: { qa_selector: 'audit_events_settings_link' } do
%span= _('Audit Events')
- elsif show_discover_project_security?(@project) - elsif show_discover_project_security?(@project)
= nav_link(path: project_security_discover_path(@project)) do = nav_link(path: project_security_discover_path(@project)) do
= link_to project_security_discover_path(@project) do = link_to project_security_discover_path(@project) do
......
- return unless @project.feature_available?(:audit_events) || show_promotions?
= nav_link(controller: :audit_events) do
= link_to project_audit_events_path(@project), title: "Audit Events", data: { qa_selector: 'audit_events_settings_link' } do
= _('Audit Events')
---
title: Adjust Audit Events navigation and visibility
merge_request: 49794
author:
type: changed
...@@ -146,6 +146,39 @@ RSpec.describe Groups::AuditEventsController do ...@@ -146,6 +146,39 @@ RSpec.describe Groups::AuditEventsController do
end end
end end
context 'authorized as user without admin group permission' do
let_it_be(:developer) { create(:user) }
let(:audit_logs_params) do
{
group_id: group.to_param, sort: sort,
entity_type: entity_type, entity_id: entity_id,
author_id: owner.id
}
end
let(:request) do
get :index, params: audit_logs_params
end
before do
stub_licensed_features(audit_events: true)
group.add_developer(developer)
sign_in(developer)
end
it 'returns only events by current user' do
developer_event = create(:group_audit_event, entity_id: group.id, author_id: developer.id)
create(:group_audit_event, entity_id: group.id, author_id: owner.id)
request
actual_event_ids = assigns(:events).map { |event| event[:id] }
expect(actual_event_ids).to contain_exactly(developer_event.id)
end
end
context 'unauthorized' do context 'unauthorized' do
let(:request) do let(:request) do
get :index, params: { group_id: group.to_param, sort: sort, entity_type: entity_type, entity_id: entity_id } get :index, params: { group_id: group.to_param, sort: sort, entity_type: entity_type, entity_id: entity_id }
......
...@@ -151,6 +151,39 @@ RSpec.describe Projects::AuditEventsController do ...@@ -151,6 +151,39 @@ RSpec.describe Projects::AuditEventsController do
end end
end end
context 'authorized as user without admin project permission' do
let_it_be(:developer) { create(:user) }
let(:audit_logs_params) do
{
namespace_id: project.namespace.to_param, project_id: project.to_param,
sort: sort, entity_type: entity_type, entity_id: entity_id,
author_id: maintainer.id
}
end
let(:request) do
get :index, params: audit_logs_params
end
before do
stub_licensed_features(audit_events: true)
project.add_developer(developer)
sign_in(developer)
end
it 'returns only events by current user' do
developer_event = create(:project_audit_event, entity_id: project.id, author_id: developer.id)
create(:project_audit_event, entity_id: project.id, author_id: maintainer.id)
request
actual_event_ids = assigns(:events).map { |event| event[:id] }
expect(actual_event_ids).to contain_exactly(developer_event.id)
end
end
context 'unauthorized' do context 'unauthorized' do
before do before do
stub_licensed_features(audit_events: true) stub_licensed_features(audit_events: true)
......
...@@ -29,14 +29,14 @@ RSpec.describe 'Groups > Audit Events', :js do ...@@ -29,14 +29,14 @@ RSpec.describe 'Groups > Audit Events', :js do
end end
it 'does not have Audit Events button in head nav bar' do it 'does not have Audit Events button in head nav bar' do
visit edit_group_path(group) visit group_security_dashboard_path(group)
expect(page).not_to have_link('Audit Events') expect(page).not_to have_link('Audit Events')
end end
end end
it 'has Audit Events button in head nav bar' do it 'has Audit Events button in head nav bar' do
visit edit_group_path(group) visit group_security_dashboard_path(group)
expect(page).to have_link('Audit Events') expect(page).to have_link('Audit Events')
end end
...@@ -52,9 +52,10 @@ RSpec.describe 'Groups > Audit Events', :js do ...@@ -52,9 +52,10 @@ RSpec.describe 'Groups > Audit Events', :js do
click_button 'Maintainer' click_button 'Maintainer'
end end
find(:link, text: 'Settings').click page.within('.qa-group-sidebar') do
find(:link, text: 'Security & Compliance').click
click_link 'Audit Events' click_link 'Audit Events'
end
page.within('.audit-log-table') do page.within('.audit-log-table') do
expect(page).to have_content 'Changed access level from Developer to Maintainer' expect(page).to have_content 'Changed access level from Developer to Maintainer'
......
...@@ -122,23 +122,23 @@ RSpec.describe 'Group navbar' do ...@@ -122,23 +122,23 @@ RSpec.describe 'Group navbar' do
end end
context 'when security dashboard is available' do context 'when security dashboard is available' do
let(:security_and_compliance_nav_item) do
{
nav_item: _('Security & Compliance'),
nav_sub_items: [
_('Security Dashboard'),
_('Vulnerability Report'),
_('Compliance'),
_('Audit Events')
]
}
end
before do before do
group.add_owner(user) group.add_owner(user)
stub_licensed_features(security_dashboard: true, group_level_compliance_dashboard: true) stub_licensed_features(security_dashboard: true, group_level_compliance_dashboard: true)
insert_after_nav_item(
_('Merge Requests'),
new_nav_item: {
nav_item: _('Security & Compliance'),
nav_sub_items: [
_('Security Dashboard'),
_('Vulnerability Report'),
_('Compliance')
]
}
)
insert_after_nav_item(_('Members'), new_nav_item: settings_nav_item) insert_after_nav_item(_('Members'), new_nav_item: settings_nav_item)
insert_after_nav_item(_('Settings'), new_nav_item: administration_nav_item) insert_after_nav_item(_('Settings'), new_nav_item: administration_nav_item)
......
...@@ -48,8 +48,8 @@ RSpec.describe 'Projects > Audit Events', :js do ...@@ -48,8 +48,8 @@ RSpec.describe 'Projects > Audit Events', :js do
expect(reqs.first.status_code).to eq(200) expect(reqs.first.status_code).to eq(200)
end end
it 'does not have Audit Events button in head nav bar' do it 'has Audit Events button in head nav bar' do
visit edit_project_path(project) visit project_audit_events_path(project)
expect(page).to have_link('Audit Events') expect(page).to have_link('Audit Events')
end end
...@@ -62,7 +62,7 @@ RSpec.describe 'Projects > Audit Events', :js do ...@@ -62,7 +62,7 @@ RSpec.describe 'Projects > Audit Events', :js do
end end
it 'has Audit Events button in head nav bar' do it 'has Audit Events button in head nav bar' do
visit edit_project_path(project) visit project_audit_events_path(project)
expect(page).to have_link('Audit Events') expect(page).to have_link('Audit Events')
end end
...@@ -117,9 +117,10 @@ RSpec.describe 'Projects > Audit Events', :js do ...@@ -117,9 +117,10 @@ RSpec.describe 'Projects > Audit Events', :js do
click_link 'Maintainer' click_link 'Maintainer'
end end
find(:link, text: 'Settings').click page.within('.qa-project-sidebar') do
find(:link, text: 'Security & Compliance').click
click_link 'Audit Events' click_link 'Audit Events'
end
page.within('.audit-log-table') do page.within('.audit-log-table') do
expect(page).to have_content 'Changed access level from Developer to Maintainer' expect(page).to have_content 'Changed access level from Developer to Maintainer'
...@@ -148,7 +149,7 @@ RSpec.describe 'Projects > Audit Events', :js do ...@@ -148,7 +149,7 @@ RSpec.describe 'Projects > Audit Events', :js do
end end
page.within('.qa-project-sidebar') do page.within('.qa-project-sidebar') do
find(:link, text: 'Settings').click find(:link, text: 'Security & Compliance').click
click_link 'Audit Events' click_link 'Audit Events'
end end
......
...@@ -34,22 +34,22 @@ RSpec.describe 'Project navbar' do ...@@ -34,22 +34,22 @@ RSpec.describe 'Project navbar' do
end end
context 'when security dashboard is available' do context 'when security dashboard is available' do
let(:security_and_compliance_nav_item) do
{
nav_item: _('Security & Compliance'),
nav_sub_items: [
_('Security Dashboard'),
_('Vulnerability Report'),
s_('OnDemandScans|On-demand Scans'),
_('Configuration'),
_('Audit Events')
]
}
end
before do before do
stub_licensed_features(security_dashboard: true, security_on_demand_scans: true) stub_licensed_features(security_dashboard: true, security_on_demand_scans: true)
insert_after_nav_item(
_('CI / CD'),
new_nav_item: {
nav_item: _('Security & Compliance'),
nav_sub_items: [
_('Security Dashboard'),
_('Vulnerability Report'),
s_('OnDemandScans|On-demand Scans'),
_('Configuration')
]
}
)
visit project_path(project) visit project_path(project)
end end
......
...@@ -10,6 +10,7 @@ RSpec.describe Groups::SecurityFeaturesHelper do ...@@ -10,6 +10,7 @@ RSpec.describe Groups::SecurityFeaturesHelper do
before do before do
allow(helper).to receive(:current_user).and_return(user) allow(helper).to receive(:current_user).and_return(user)
allow(helper).to receive(:can?).and_return(false)
end end
describe '#group_level_security_dashboard_available?' do describe '#group_level_security_dashboard_available?' do
...@@ -74,6 +75,27 @@ RSpec.describe Groups::SecurityFeaturesHelper do ...@@ -74,6 +75,27 @@ RSpec.describe Groups::SecurityFeaturesHelper do
end end
end end
describe '#group_level_audit_events_available?' do
where(:audit_events_feature_enabled, :read_group_audit_events_permission, :result) do
true | false | false
true | true | true
false | false | false
false | true | false
end
with_them do
before do
stub_licensed_features(audit_events: audit_events_feature_enabled)
allow(helper).to receive(:can?).with(user, :read_group_audit_events, group)
.and_return(read_group_audit_events_permission)
end
it 'returns the expected result' do
expect(helper.group_level_audit_events_available?(group)).to eq(result)
end
end
end
describe '#primary_group_level_security_feature_path' do describe '#primary_group_level_security_feature_path' do
subject { helper.primary_group_level_security_feature_path(group) } subject { helper.primary_group_level_security_feature_path(group) }
...@@ -107,11 +129,22 @@ RSpec.describe Groups::SecurityFeaturesHelper do ...@@ -107,11 +129,22 @@ RSpec.describe Groups::SecurityFeaturesHelper do
end end
end end
context 'group_level_audit_events is available' do
before do
allow(helper).to receive(:group_level_audit_events_available?).with(group).and_return(true)
end
it 'returns path to audit events' do
expect(subject).to eq(group_audit_events_path(group))
end
end
context 'when no security features are available' do context 'when no security features are available' do
before do before do
allow(helper).to receive(:group_level_security_dashboard_available?).with(group).and_return(false) allow(helper).to receive(:group_level_security_dashboard_available?).with(group).and_return(false)
allow(helper).to receive(:group_level_compliance_dashboard_available?).with(group).and_return(false) allow(helper).to receive(:group_level_compliance_dashboard_available?).with(group).and_return(false)
allow(helper).to receive(:group_level_credentials_inventory_available?).with(group).and_return(false) allow(helper).to receive(:group_level_credentials_inventory_available?).with(group).and_return(false)
allow(helper).to receive(:group_level_audit_events_available?).with(group).and_return(false)
end end
it 'returns nil' do it 'returns nil' do
......
...@@ -220,6 +220,7 @@ RSpec.describe ProjectsHelper do ...@@ -220,6 +220,7 @@ RSpec.describe ProjectsHelper do
projects/threat_monitoring#show projects/threat_monitoring#show
projects/threat_monitoring#new projects/threat_monitoring#new
projects/threat_monitoring#edit projects/threat_monitoring#edit
projects/audit_events#index
] ]
end end
...@@ -276,6 +277,7 @@ RSpec.describe ProjectsHelper do ...@@ -276,6 +277,7 @@ RSpec.describe ProjectsHelper do
before do before do
allow(helper).to receive(:can?) { false } allow(helper).to receive(:can?) { false }
allow(helper).to receive(:current_user).and_return(user)
end end
subject do subject do
...@@ -304,6 +306,64 @@ RSpec.describe ProjectsHelper do ...@@ -304,6 +306,64 @@ RSpec.describe ProjectsHelper do
end end
end end
describe '#top_level_link' do
let(:user) { build(:user) }
subject { helper.top_level_link(project) }
before do
allow(project).to receive(:feature_available?).and_return(false)
allow(helper).to receive(:can?).and_return(false)
allow(helper).to receive(:current_user).and_return(user)
end
it 'shows security/dashboard path' do
allow(helper).to receive(:can?).with(user, :read_project_security_dashboard, project).and_return(true)
is_expected.to eq("/#{project.full_path}/-/security/dashboard")
end
it 'shows audit_events path' do
allow(helper).to receive(:can?).with(user, :read_project_audit_events, project).and_return(true)
allow(project).to receive(:feature_available?).with(:audit_events).and_return(true)
is_expected.to eq("/#{project.full_path}/-/audit_events")
end
it 'shows dependencies path' do
is_expected.to eq("/#{project.full_path}/-/dependencies")
end
end
describe '#top_level_qa_selector' do
let(:user) { build(:user) }
subject { helper.top_level_qa_selector(project) }
before do
allow(project).to receive(:feature_available?).and_return(false)
allow(helper).to receive(:can?).and_return(false)
allow(helper).to receive(:current_user).and_return(user)
end
it 'shows security dashboard selector' do
allow(helper).to receive(:can?).with(user, :read_project_security_dashboard, project).and_return(true)
is_expected.to eq('security_dashboard_link')
end
it 'shows audit events selector' do
allow(helper).to receive(:can?).with(user, :read_project_audit_events, project).and_return(true)
allow(project).to receive(:feature_available?).with(:audit_events).and_return(true)
is_expected.to eq('audit_events_settings_link')
end
it 'shows dependencies selector' do
is_expected.to eq('dependency_list_link')
end
end
describe '#show_discover_project_security?' do describe '#show_discover_project_security?' do
using RSpec::Parameterized::TableSyntax using RSpec::Parameterized::TableSyntax
let(:user) { create(:user) } let(:user) { create(:user) }
......
...@@ -189,6 +189,40 @@ RSpec.describe 'layouts/nav/sidebar/_group' do ...@@ -189,6 +189,40 @@ RSpec.describe 'layouts/nav/sidebar/_group' do
end end
end end
context 'when audit events feature is enabled' do
before do
stub_licensed_features(audit_events: true)
end
context 'when the user does not have access to Audit Events' do
before do
group.add_guest(user)
allow(view).to receive(:current_user).and_return(user)
end
it 'is not visible' do
render
expect(rendered).not_to have_link 'Security & Compliance'
expect(rendered).not_to have_link 'Audit Events'
end
end
context 'when the user has access to Audit Events' do
before do
group.add_owner(user)
allow(view).to receive(:current_user).and_return(user)
end
it 'is visible' do
render
expect(rendered).to have_link 'Security & Compliance'
expect(rendered).to have_link 'Audit Events'
end
end
end
context 'when security dashboard feature is disabled' do context 'when security dashboard feature is disabled' do
let(:group) { create(:group_with_plan, plan: :bronze_plan) } let(:group) { create(:group_with_plan, plan: :bronze_plan) }
......
...@@ -92,12 +92,14 @@ RSpec.describe 'layouts/nav/sidebar/_project' do ...@@ -92,12 +92,14 @@ RSpec.describe 'layouts/nav/sidebar/_project' do
before do before do
allow(view).to receive(:can?).with(nil, :read_dependencies, project).and_return(can_read_dependencies) allow(view).to receive(:can?).with(nil, :read_dependencies, project).and_return(can_read_dependencies)
allow(view).to receive(:can?).with(nil, :read_project_security_dashboard, project).and_return(can_read_dashboard) allow(view).to receive(:can?).with(nil, :read_project_security_dashboard, project).and_return(can_read_dashboard)
allow(view).to receive(:can?).with(nil, :read_project_audit_events, project).and_return(can_read_project_audit_events)
render render
end end
describe 'when the user has full permissions' do describe 'when the user has full permissions' do
let(:can_read_dashboard) { true } let(:can_read_dashboard) { true }
let(:can_read_dependencies) { true } let(:can_read_dependencies) { true }
let(:can_read_project_audit_events) { true }
it 'top level navigation link is visible' do it 'top level navigation link is visible' do
expect(rendered).to have_link('Security & Compliance', href: project_security_dashboard_index_path(project)) expect(rendered).to have_link('Security & Compliance', href: project_security_dashboard_index_path(project))
...@@ -114,11 +116,16 @@ RSpec.describe 'layouts/nav/sidebar/_project' do ...@@ -114,11 +116,16 @@ RSpec.describe 'layouts/nav/sidebar/_project' do
it 'dependency list link is visible' do it 'dependency list link is visible' do
expect(rendered).to have_link('Dependency List', href: project_dependencies_path(project)) expect(rendered).to have_link('Dependency List', href: project_dependencies_path(project))
end end
it 'audit events link is visible' do
expect(rendered).to have_link('Audit Events', href: project_audit_events_path(project))
end
end end
describe 'when the user can view only security dashboard' do describe 'when the user can view only security dashboard' do
let(:can_read_dashboard) { true } let(:can_read_dashboard) { true }
let(:can_read_dependencies) { false } let(:can_read_dependencies) { false }
let(:can_read_project_audit_events) { false }
it 'top level navigation link is visible' do it 'top level navigation link is visible' do
expect(rendered).to have_link('Security & Compliance', href: project_security_dashboard_index_path(project)) expect(rendered).to have_link('Security & Compliance', href: project_security_dashboard_index_path(project))
...@@ -135,11 +142,16 @@ RSpec.describe 'layouts/nav/sidebar/_project' do ...@@ -135,11 +142,16 @@ RSpec.describe 'layouts/nav/sidebar/_project' do
it 'dependency list link is not visible' do it 'dependency list link is not visible' do
expect(rendered).not_to have_link('Dependency List', href: project_dependencies_path(project)) expect(rendered).not_to have_link('Dependency List', href: project_dependencies_path(project))
end end
it 'audit events link is not visible' do
expect(rendered).not_to have_link('Audit Events', href: project_audit_events_path(project))
end
end end
describe 'when the user can view only dependency list' do describe 'when the user can view only dependency list' do
let(:can_read_dashboard) { false } let(:can_read_dashboard) { false }
let(:can_read_dependencies) { true } let(:can_read_dependencies) { true }
let(:can_read_project_audit_events) { false }
it 'top level navigation link is visible' do it 'top level navigation link is visible' do
expect(rendered).to have_link('Security & Compliance', href: project_dependencies_path(project)) expect(rendered).to have_link('Security & Compliance', href: project_dependencies_path(project))
...@@ -156,11 +168,42 @@ RSpec.describe 'layouts/nav/sidebar/_project' do ...@@ -156,11 +168,42 @@ RSpec.describe 'layouts/nav/sidebar/_project' do
it 'dependency list link is visible' do it 'dependency list link is visible' do
expect(rendered).to have_link('Dependency List', href: project_dependencies_path(project)) expect(rendered).to have_link('Dependency List', href: project_dependencies_path(project))
end end
it 'audit events link is not visible' do
expect(rendered).not_to have_link('Audit Events', href: project_audit_events_path(project))
end
end
describe 'when the user can view only audit events' do
let(:can_read_dashboard) { false }
let(:can_read_dependencies) { false }
let(:can_read_project_audit_events) { true }
it 'top level navigation link is visible' do
expect(rendered).to have_link('Security & Compliance', href: project_audit_events_path(project))
end
it 'security dashboard link is not visible' do
expect(rendered).not_to have_link('Security Dashboard', href: project_security_dashboard_index_path(project))
end
it 'security configuration link is not visible' do
expect(rendered).not_to have_link('Configuration', href: project_security_configuration_path(project))
end
it 'dependency list link is not visible' do
expect(rendered).not_to have_link('Dependency List', href: project_dependencies_path(project))
end
it 'audit events link is visible' do
expect(rendered).to have_link('Audit Events', href: project_audit_events_path(project))
end
end end
describe 'when the user has no permissions' do describe 'when the user has no permissions' do
let(:can_read_dependencies) { false } let(:can_read_dependencies) { false }
let(:can_read_dashboard) { false } let(:can_read_dashboard) { false }
let(:can_read_project_audit_events) { false }
it 'top level navigation link is visible' do it 'top level navigation link is visible' do
expect(rendered).not_to have_link('Security & Compliance', href: project_security_dashboard_index_path(project)) expect(rendered).not_to have_link('Security & Compliance', href: project_security_dashboard_index_path(project))
...@@ -177,6 +220,10 @@ RSpec.describe 'layouts/nav/sidebar/_project' do ...@@ -177,6 +220,10 @@ RSpec.describe 'layouts/nav/sidebar/_project' do
it 'dependency list link is not visible' do it 'dependency list link is not visible' do
expect(rendered).not_to have_link('Dependency List', href: project_dependencies_path(project)) expect(rendered).not_to have_link('Dependency List', href: project_dependencies_path(project))
end end
it 'audit events link is not visible' do
expect(rendered).not_to have_link('Audit Events', href: project_audit_events_path(project))
end
end end
end end
......
...@@ -33,7 +33,6 @@ module QA ...@@ -33,7 +33,6 @@ module QA
view 'ee/app/views/groups/ee/_settings_nav.html.haml' do view 'ee/app/views/groups/ee/_settings_nav.html.haml' do
element :ldap_synchronization_link element :ldap_synchronization_link
element :audit_events_settings_link
end end
view 'ee/app/views/layouts/nav/ee/_epic_link.html.haml' do view 'ee/app/views/layouts/nav/ee/_epic_link.html.haml' do
element :group_epics_link element :group_epics_link
...@@ -44,6 +43,7 @@ module QA ...@@ -44,6 +43,7 @@ module QA
element :group_secure_submenu element :group_secure_submenu
element :security_dashboard_link element :security_dashboard_link
element :vulnerability_report_link element :vulnerability_report_link
element :audit_events_settings_link
end end
view 'ee/app/views/layouts/nav/_group_insights_link.html.haml' do view 'ee/app/views/layouts/nav/_group_insights_link.html.haml' do
...@@ -57,8 +57,8 @@ module QA ...@@ -57,8 +57,8 @@ module QA
end end
def go_to_audit_events_settings def go_to_audit_events_settings
hover_element(:group_settings_item) do hover_element(:security_compliance_link) do
within_submenu(:group_sidebar_submenu) do within_submenu(:group_secure_submenu) do
click_element(:audit_events_settings_link) click_element(:audit_events_settings_link)
end end
end end
......
...@@ -14,6 +14,7 @@ module QA ...@@ -14,6 +14,7 @@ module QA
element :security_dashboard_link element :security_dashboard_link
element :dependency_list_link element :dependency_list_link
element :vulnerability_report_link element :vulnerability_report_link
element :audit_events_settings_link
end end
end end
end end
...@@ -47,6 +48,14 @@ module QA ...@@ -47,6 +48,14 @@ module QA
yield yield
end end
end end
def go_to_audit_events_settings
hover_security_compliance do
within_submenu do
click_element :audit_events_settings_link
end
end
end
end end
end end
end end
......
...@@ -11,18 +11,6 @@ module QA ...@@ -11,18 +11,6 @@ module QA
def self.prepended(base) def self.prepended(base)
base.class_eval do base.class_eval do
prepend QA::Page::Project::SubMenus::Common prepend QA::Page::Project::SubMenus::Common
view 'ee/app/views/projects/sidebar/_settings_audit_events.html.haml' do
element :audit_events_settings_link
end
end
end
def go_to_audit_events_settings
hover_settings do
within_submenu do
click_element :audit_events_settings_link
end
end end
end end
......
...@@ -33,6 +33,7 @@ RSpec.describe 'Group navbar' do ...@@ -33,6 +33,7 @@ RSpec.describe 'Group navbar' do
nav_item: _('Merge Requests'), nav_item: _('Merge Requests'),
nav_sub_items: [] nav_sub_items: []
}, },
(security_and_compliance_nav_item if Gitlab.ee?),
(push_rules_nav_item if Gitlab.ee?), (push_rules_nav_item if Gitlab.ee?),
{ {
nav_item: _('Kubernetes'), nav_item: _('Kubernetes'),
......
...@@ -416,6 +416,7 @@ RSpec.describe ProjectsHelper do ...@@ -416,6 +416,7 @@ RSpec.describe ProjectsHelper do
describe '#get_project_nav_tabs' do describe '#get_project_nav_tabs' do
before do before do
allow(helper).to receive(:current_user).and_return(user)
allow(helper).to receive(:can?) { true } allow(helper).to receive(:can?) { true }
end end
......
...@@ -14,6 +14,15 @@ RSpec.shared_context 'project navbar structure' do ...@@ -14,6 +14,15 @@ RSpec.shared_context 'project navbar structure' do
} }
end end
let(:security_and_compliance_nav_item) do
{
nav_item: _('Security & Compliance'),
nav_sub_items: [
_('Audit Events')
]
}
end
let(:structure) do let(:structure) do
[ [
{ {
...@@ -62,6 +71,7 @@ RSpec.shared_context 'project navbar structure' do ...@@ -62,6 +71,7 @@ RSpec.shared_context 'project navbar structure' do
_('Schedules') _('Schedules')
] ]
}, },
(security_and_compliance_nav_item if Gitlab.ee?),
{ {
nav_item: _('Operations'), nav_item: _('Operations'),
nav_sub_items: [ nav_sub_items: [
...@@ -101,8 +111,7 @@ RSpec.shared_context 'project navbar structure' do ...@@ -101,8 +111,7 @@ RSpec.shared_context 'project navbar structure' do
_('Access Tokens'), _('Access Tokens'),
_('Repository'), _('Repository'),
_('CI / CD'), _('CI / CD'),
_('Operations'), _('Operations')
(_('Audit Events') if Gitlab.ee?)
].compact ].compact
} }
].compact ].compact
...@@ -128,8 +137,7 @@ RSpec.shared_context 'group navbar structure' do ...@@ -128,8 +137,7 @@ RSpec.shared_context 'group navbar structure' do
_('Projects'), _('Projects'),
_('Repository'), _('Repository'),
_('CI / CD'), _('CI / CD'),
_('Webhooks'), _('Webhooks')
_('Audit Events')
] ]
} }
end end
...@@ -143,6 +151,15 @@ RSpec.shared_context 'group navbar structure' do ...@@ -143,6 +151,15 @@ RSpec.shared_context 'group navbar structure' do
} }
end end
let(:security_and_compliance_nav_item) do
{
nav_item: _('Security & Compliance'),
nav_sub_items: [
_('Audit Events')
]
}
end
let(:push_rules_nav_item) do let(:push_rules_nav_item) do
{ {
nav_item: _('Push Rules'), nav_item: _('Push Rules'),
...@@ -172,6 +189,7 @@ RSpec.shared_context 'group navbar structure' do ...@@ -172,6 +189,7 @@ RSpec.shared_context 'group navbar structure' do
nav_item: _('Merge Requests'), nav_item: _('Merge Requests'),
nav_sub_items: [] nav_sub_items: []
}, },
(security_and_compliance_nav_item if Gitlab.ee?),
(push_rules_nav_item if Gitlab.ee?), (push_rules_nav_item if Gitlab.ee?),
{ {
nav_item: _('Kubernetes'), nav_item: _('Kubernetes'),
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment