Commit 7ba4da68 authored by Arturo Herrero's avatar Arturo Herrero

Merge branch '326432-fj-add-new-security-menu' into 'master'

Add Security and Compliance menu

See merge request gitlab-org/gitlab!60368
parents 87340e3a a784f717
......@@ -378,19 +378,6 @@ module ProjectsHelper
private
def can_read_security_configuration?(project, current_user)
can?(current_user, :access_security_and_compliance, project) &&
can?(current_user, :read_security_configuration, project)
end
def get_project_security_nav_tabs(project, current_user)
if can_read_security_configuration?(project, current_user)
[:security_and_compliance, :security_configuration]
else
[]
end
end
# rubocop:disable Metrics/CyclomaticComplexity
def get_project_nav_tabs(project, current_user)
nav_tabs = [:home]
......@@ -400,8 +387,6 @@ module ProjectsHelper
nav_tabs << :releases if can?(current_user, :read_release, project)
end
nav_tabs += get_project_security_nav_tabs(project, current_user)
if project.repo_exists? && can?(current_user, :read_merge_request, project)
nav_tabs << :merge_requests
end
......@@ -723,12 +708,6 @@ module ProjectsHelper
"#{request.path}?#{options.to_param}"
end
def sidebar_security_configuration_paths
%w[
projects/security/configuration#show
]
end
def sidebar_settings_paths
%w[
projects#edit
......@@ -767,10 +746,6 @@ module ProjectsHelper
]
end
def sidebar_security_paths
%w[projects/security/configuration#show]
end
def user_can_see_auto_devops_implicitly_enabled_banner?(project, user)
Ability.allowed?(user, :admin_project, project) &&
project.has_auto_devops_implicitly_enabled? &&
......
......@@ -45,3 +45,5 @@ module SidebarsHelper
}
end
end
SidebarsHelper.prepend_if_ee('EE::SidebarsHelper')
- if project_nav_tab? :security_and_compliance
= render_if_exists 'layouts/nav/sidebar/project_security_link' # EE-specific
- if project_nav_tab? :operations
= nav_link(controller: sidebar_operations_paths) do
= link_to sidebar_operations_link_path, class: 'shortcuts-operations', data: { qa_selector: 'operations_link' } do
......
- top_level_link = project_security_configuration_path(@project)
- top_level_qa_selector = 'security_configuration_link'
- if any_project_nav_tab?([:security_configuration])
= nav_link(path: sidebar_security_paths) do
= link_to top_level_link, data: { qa_selector: top_level_qa_selector } do
.nav-icon-container
= sprite_icon('shield')
%span.nav-item-name
= _('Security & Compliance')
%ul.sidebar-sub-level-items
= nav_link(path: sidebar_security_paths, html_options: { class: "fly-out-top-item" } ) do
= link_to top_level_link do
%strong.fly-out-top-item-name
= _('Security & Compliance')
%li.divider.fly-out-top-item
- if project_nav_tab?(:security_configuration)
= nav_link(path: sidebar_security_configuration_paths) do
= link_to project_security_configuration_path(@project), title: _('Configuration'), data: { qa_selector: 'security_configuration_link'} do
%span= _('Configuration')
......@@ -171,54 +171,6 @@ module EE
@project.feature_available?(:merge_trains)
end
override :sidebar_security_paths
def sidebar_security_paths
super + %w[
projects/security/sast_configuration#show
projects/security/api_fuzzing_configuration#show
projects/security/vulnerabilities#show
projects/security/vulnerability_report#index
projects/security/dashboard#index
projects/on_demand_scans#index
projects/on_demand_scans#new
projects/on_demand_scans#edit
projects/security/dast_profiles#show
projects/security/dast_site_profiles#new
projects/security/dast_site_profiles#edit
projects/security/dast_scanner_profiles#new
projects/security/dast_scanner_profiles#edit
projects/dependencies#index
projects/licenses#index
projects/threat_monitoring#show
projects/threat_monitoring#new
projects/threat_monitoring#edit
projects/threat_monitoring#alert_details
projects/security/policies#show
projects/audit_events#index
]
end
def sidebar_on_demand_scans_paths
%w[
projects/on_demand_scans#index
projects/on_demand_scans#new
projects/on_demand_scans#edit
]
end
override :sidebar_security_configuration_paths
def sidebar_security_configuration_paths
super + %w[
projects/security/sast_configuration#show
projects/security/api_fuzzing_configuration#show
projects/security/dast_profiles#show
projects/security/dast_site_profiles#new
projects/security/dast_site_profiles#edit
projects/security/dast_scanner_profiles#new
projects/security/dast_scanner_profiles#edit
]
end
def size_limit_message(project)
show_lfs = project.lfs_enabled? ? 'including LFS files' : ''
......@@ -300,20 +252,6 @@ module EE
tabs.any? { |tab| project_nav_tab?(tab) }
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)
!!current_user &&
::Gitlab.com? &&
......@@ -336,54 +274,6 @@ module EE
private
override :can_read_security_configuration?
def can_read_security_configuration?(project, current_user)
super || (project.feature_available?(:security_dashboard) &&
can?(current_user, :read_project_security_dashboard, project))
end
override :get_project_security_nav_tabs
def get_project_security_nav_tabs(project, current_user)
return [] unless can?(current_user, :access_security_and_compliance, project)
nav_tabs = super.union([:security_and_compliance])
if can?(current_user, :read_project_security_dashboard, project)
nav_tabs << :security
end
if can?(current_user, :read_on_demand_scans, @project)
nav_tabs << :on_demand_scans
end
if can?(current_user, :read_dependencies, project)
nav_tabs << :dependencies
end
if can?(current_user, :read_licenses, project)
nav_tabs << :licenses
end
if can?(current_user, :read_threat_monitoring, project)
nav_tabs << :threat_monitoring
end
if can?(current_user, :security_orchestration_policies, project)
nav_tabs << :security_orchestration_policies
end
if show_audit_events?(project)
nav_tabs << :audit_events
end
nav_tabs
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)
{
project: project.path,
......
# frozen_string_literal: true
module EE
module SidebarsHelper
extend ::Gitlab::Utils::Override
override :project_sidebar_context_data
def project_sidebar_context_data(project, user, current_ref)
super.merge({
show_promotions: show_promotions?(user),
show_discover_project_security: show_discover_project_security?(project)
})
end
end
end
- on_demand_scans_path = new_project_on_demand_scan_path(@project)
- if any_project_nav_tab?([:security, :security_configuration, :dependencies, :licenses, :audit_events])
= nav_link(path: sidebar_security_paths) do
= link_to top_level_link(@project), data: { qa_selector: top_level_qa_selector(@project) } do
.nav-icon-container
= sprite_icon('shield')
%span.nav-item-name
= _('Security & Compliance')
%ul.sidebar-sub-level-items
= nav_link(path: sidebar_security_paths, html_options: { class: "fly-out-top-item" } ) do
= link_to top_level_link(@project) do
%strong.fly-out-top-item-name
= _('Security & Compliance')
%li.divider.fly-out-top-item
- if project_nav_tab?(:security)
= nav_link(path: 'projects/security/dashboard#index') do
= link_to project_security_dashboard_index_path(@project), title: _('Security Dashboard'), data: { qa_selector: 'security_dashboard_link' } do
%span= _('Security Dashboard')
= nav_link(path: ['projects/security/vulnerability_report#index', 'projects/security/vulnerabilities#show']) do
= link_to project_security_vulnerability_report_index_path(@project), title: _('Vulnerability Report'), data: { qa_selector: 'vulnerability_report_link' } do
%span= _('Vulnerability Report')
- if project_nav_tab?(:on_demand_scans)
= nav_link(path: sidebar_on_demand_scans_paths) do
= link_to on_demand_scans_path, title: s_('OnDemandScans|On-demand Scans'), data: { qa_selector: 'on_demand_scans_link' } do
%span= s_('OnDemandScans|On-demand Scans')
- if project_nav_tab?(:dependencies)
= nav_link(path: 'projects/dependencies#index') do
= link_to project_dependencies_path(@project), title: _('Dependency List'), data: { qa_selector: 'dependency_list_link' } do
%span= _('Dependency List')
- if project_nav_tab?(:licenses)
= nav_link(path: 'projects/licenses#index') do
= link_to project_licenses_path(@project), title: _('License Compliance'), data: { qa_selector: 'licenses_list_link' } do
%span= _('License Compliance')
- if project_nav_tab?(:threat_monitoring)
= nav_link(controller: ['projects/threat_monitoring']) do
= link_to project_threat_monitoring_path(@project), title: _('Threat Monitoring') do
%span= _('Threat Monitoring')
- if project_nav_tab?(:security_orchestration_policies) && Feature.enabled?(:security_orchestration_policies_configuration, @project)
= nav_link(controller: ['projects/security/policies']) do
= link_to project_security_policy_path(@project), title: _('Scan Policies') do
%span= _('Scan Policies')
- if project_nav_tab?(:security_configuration)
= nav_link(path: sidebar_security_configuration_paths) do
= link_to project_security_configuration_path(@project), title: _('Configuration'), data: { qa_selector: 'security_configuration_link'} do
%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)
= nav_link(path: project_security_discover_path(@project)) do
= link_to project_security_discover_path(@project) do
.nav-icon-container
= sprite_icon('shield')
%span.nav-item-name
= _('Security & Compliance')
# frozen_string_literal: true
module EE
module Sidebars
module Projects
module Menus
module SecurityComplianceMenu
extend ::Gitlab::Utils::Override
override :configure_menu_items
def configure_menu_items
return false unless can?(context.current_user, :access_security_and_compliance, context.project)
add_item(security_dashboard_menu_item)
add_item(vulnerability_report_menu_item)
add_item(on_demand_scans_menu_item)
add_item(dependencies_menu_item)
add_item(license_compliance_menu_item)
add_item(threat_monitoring_menu_item)
add_item(scan_policies_menu_item)
add_item(configuration_menu_item)
add_item(audit_events_menu_item)
true
end
override :link
def link
return project_security_discover_path(context.project) unless has_items?
return security_dashboard_menu_item.link if security_dashboard_menu_item
return audit_events_menu_item.link if audit_events_menu_item
return dependencies_menu_item.link if dependencies_menu_item
items.first.link
end
override :render?
def render?
super || context.show_discover_project_security
end
private
override :configuration_menu_item_paths
def configuration_menu_item_paths
super + %w[
projects/security/sast_configuration#show
projects/security/api_fuzzing_configuration#show
projects/security/dast_profiles#show
projects/security/dast_site_profiles#new
projects/security/dast_site_profiles#edit
projects/security/dast_scanner_profiles#new
projects/security/dast_scanner_profiles#edit
]
end
override :render_configuration_menu_item?
def render_configuration_menu_item?
super ||
(context.project.licensed_feature_available?(:security_dashboard) && can?(context.current_user, :read_project_security_dashboard, context.project))
end
def security_dashboard_menu_item
strong_memoize(:security_dashboard_menu_item) do
next unless can?(context.current_user, :read_project_security_dashboard, context.project)
::Sidebars::MenuItem.new(
title: _('Security Dashboard'),
link: project_security_dashboard_index_path(context.project),
active_routes: { path: 'projects/security/dashboard#index' },
item_id: :dashboard
)
end
end
def vulnerability_report_menu_item
strong_memoize(:vulnerability_report_menu_item) do
next unless can?(context.current_user, :read_project_security_dashboard, context.project)
::Sidebars::MenuItem.new(
title: _('Vulnerability Report'),
link: project_security_vulnerability_report_index_path(context.project),
active_routes: { path: %w[projects/security/vulnerability_report#index projects/security/vulnerabilities#show] },
item_id: :vulnerability_report
)
end
end
def on_demand_scans_menu_item
strong_memoize(:on_demand_scans_menu_item) do
next unless can?(context.current_user, :read_on_demand_scans, context.project)
::Sidebars::MenuItem.new(
title: s_('OnDemandScans|On-demand Scans'),
link: new_project_on_demand_scan_path(context.project),
item_id: :on_demand_scans,
active_routes: { path: %w[
projects/on_demand_scans#index
projects/on_demand_scans#new
projects/on_demand_scans#edit
] }
)
end
end
def dependencies_menu_item
strong_memoize(:dependencies_menu_item) do
next unless can?(context.current_user, :read_dependencies, context.project)
::Sidebars::MenuItem.new(
title: _('Dependency List'),
link: project_dependencies_path(context.project),
active_routes: { path: 'projects/dependencies#index' },
item_id: :dependency_list
)
end
end
def license_compliance_menu_item
strong_memoize(:license_compliance_menu_item) do
next unless can?(context.current_user, :read_licenses, context.project)
::Sidebars::MenuItem.new(
title: _('License Compliance'),
link: project_licenses_path(context.project),
active_routes: { path: 'projects/licenses#index' },
item_id: :license_compliance
)
end
end
def threat_monitoring_menu_item
strong_memoize(:threat_monitoring_menu_item) do
next unless can?(context.current_user, :read_threat_monitoring, context.project)
::Sidebars::MenuItem.new(
title: _('Threat Monitoring'),
link: project_threat_monitoring_path(context.project),
active_routes: { controller: ['projects/threat_monitoring'] },
item_id: :threat_monitoring
)
end
end
def scan_policies_menu_item
strong_memoize(:scan_policies_menu_item) do
next if ::Feature.disabled?(:security_orchestration_policies_configuration, context.project)
next unless can?(context.current_user, :security_orchestration_policies, context.project)
::Sidebars::MenuItem.new(
title: _('Scan Policies'),
link: project_security_policy_path(context.project),
active_routes: { controller: ['projects/security/policies'] },
item_id: :scan_policies
)
end
end
def audit_events_menu_item
strong_memoize(:audit_events_menu_item) do
next unless can?(context.current_user, :read_project_audit_events, context.project)
next unless context.project.licensed_feature_available?(:audit_events) || context.show_promotions
::Sidebars::MenuItem.new(
title: _('Audit Events'),
link: project_audit_events_path(context.project),
active_routes: { controller: :audit_events },
item_id: :audit_events
)
end
end
end
end
end
end
end
......@@ -209,72 +209,6 @@ RSpec.describe ProjectsHelper do
end
end
describe '#sidebar_security_paths' do
let(:expected_security_paths) do
%w[
projects/security/configuration#show
projects/security/sast_configuration#show
projects/security/api_fuzzing_configuration#show
projects/security/vulnerabilities#show
projects/security/vulnerability_report#index
projects/security/dashboard#index
projects/on_demand_scans#index
projects/on_demand_scans#new
projects/on_demand_scans#edit
projects/security/dast_profiles#show
projects/security/dast_site_profiles#new
projects/security/dast_site_profiles#edit
projects/security/dast_scanner_profiles#new
projects/security/dast_scanner_profiles#edit
projects/dependencies#index
projects/licenses#index
projects/threat_monitoring#show
projects/threat_monitoring#new
projects/threat_monitoring#edit
projects/threat_monitoring#alert_details
projects/security/policies#show
projects/audit_events#index
]
end
subject { helper.sidebar_security_paths }
it { is_expected.to eq(expected_security_paths) }
end
describe '#sidebar_on_demand_scans_paths' do
let(:expected_on_demand_scans_paths) do
%w[
projects/on_demand_scans#index
projects/on_demand_scans#new
projects/on_demand_scans#edit
]
end
subject { helper.sidebar_on_demand_scans_paths }
it { is_expected.to eq(expected_on_demand_scans_paths) }
end
describe '#sidebar_security_configuration_paths' do
let(:expected_security_configuration_paths) do
%w[
projects/security/configuration#show
projects/security/sast_configuration#show
projects/security/api_fuzzing_configuration#show
projects/security/dast_profiles#show
projects/security/dast_site_profiles#new
projects/security/dast_site_profiles#edit
projects/security/dast_scanner_profiles#new
projects/security/dast_scanner_profiles#edit
]
end
subject { helper.sidebar_security_configuration_paths }
it { is_expected.to eq(expected_security_configuration_paths) }
end
describe '#get_project_nav_tabs' do
using RSpec::Parameterized::TableSyntax
......@@ -308,161 +242,6 @@ RSpec.describe ProjectsHelper do
end
end
end
describe 'Security & Compliance tabs' do
where(:ability, :nav_tabs) do
:read_project_security_dashboard | [:security]
:read_security_configuration | [:security_configuration]
:read_on_demand_scans | [:on_demand_scans]
:read_dependencies | [:dependencies]
:read_licenses | [:licenses]
:read_threat_monitoring | [:threat_monitoring]
end
with_them do
before do
allow(helper).to receive(:can?).with(user, :access_security_and_compliance, project).and_return(security_compliance_available?)
end
context 'when the "Security & Compliance" is accessible' do
let(:security_compliance_available?) { true }
context 'when the feature is not available' do
let(:feature_available?) { false }
it { is_expected.not_to include(*nav_tabs) }
end
context 'when the feature is available' do
let(:feature_available?) { true }
it { is_expected.to include(*nav_tabs) }
end
end
context 'when the "Security & Compliance" is not accessible' do
let(:security_compliance_available?) { false }
context 'when the feature is not available' do
let(:feature_available?) { false }
it { is_expected.not_to include(*nav_tabs) }
end
context 'when the feature is available' do
let(:feature_available?) { true }
it { is_expected.not_to include(*nav_tabs) }
end
end
end
end
end
describe '#top_level_link' do
let(:user) { build(:user) }
subject { helper.top_level_link(project) }
before do
allow(helper).to receive(:can?).and_return(false)
allow(helper).to receive(:current_user).and_return(user)
allow(helper).to receive(:can?).with(user, :access_security_and_compliance, project).and_return(true)
end
context 'when user can read project security dashboard and audit events' do
before do
allow(helper).to receive(:can?).with(user, :read_project_security_dashboard, project).and_return(true)
allow(helper).to receive(:can?).with(user, :read_project_audit_events, project).and_return(true)
end
it { is_expected.to eq("/#{project.full_path}/-/security/dashboard") }
end
context 'when user can read audit events' do
before do
allow(helper).to receive(:can?).with(user, :read_project_security_dashboard, project).and_return(false)
allow(helper).to receive(:can?).with(user, :read_project_audit_events, project).and_return(true)
end
context 'when the feature is enabled' do
before do
stub_licensed_features(audit_events: true)
end
it { is_expected.to eq("/#{project.full_path}/-/audit_events") }
end
context 'when the feature is disabled' do
before do
stub_licensed_features(audit_events: false)
end
it { is_expected.to eq("/#{project.full_path}/-/dependencies") }
end
end
context "when user can't read both project security dashboard and audit events" do
before do
allow(helper).to receive(:can?).with(user, :read_project_security_dashboard, project).and_return(false)
allow(helper).to receive(:can?).with(user, :read_project_audit_events, project).and_return(false)
end
it { 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(helper).to receive(:can?).and_return(false)
allow(helper).to receive(:current_user).and_return(user)
allow(helper).to receive(:can?).with(user, :access_security_and_compliance, project).and_return(true)
end
context 'when user can read project security dashboard and audit events' do
before do
allow(helper).to receive(:can?).with(user, :read_project_security_dashboard, project).and_return(true)
allow(helper).to receive(:can?).with(user, :read_project_audit_events, project).and_return(true)
end
it { is_expected.to eq('security_dashboard_link') }
end
context 'when user can read audit events' do
before do
allow(helper).to receive(:can?).with(user, :read_project_security_dashboard, project).and_return(false)
allow(helper).to receive(:can?).with(user, :read_project_audit_events, project).and_return(true)
end
context 'when the feature is enabled' do
before do
stub_licensed_features(audit_events: true)
end
it { is_expected.to eq('audit_events_settings_link') }
end
context 'when the feature is disabled' do
before do
stub_licensed_features(audit_events: false)
end
it { is_expected.to eq('dependency_list_link') }
end
end
context "when user can't read both project security dashboard and audit events" do
before do
allow(helper).to receive(:can?).with(user, :read_project_security_dashboard, project).and_return(false)
allow(helper).to receive(:can?).with(user, :read_project_audit_events, project).and_return(false)
end
it { is_expected.to eq('dependency_list_link') }
end
end
describe '#show_discover_project_security?' do
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Sidebars::Projects::Menus::SecurityComplianceMenu do
let_it_be(:project) { create(:project) }
let(:user) { project.owner }
let(:show_promotions) { true }
let(:show_discover_project_security) { true }
let(:context) { Sidebars::Projects::Context.new(current_user: user, container: project, show_promotions: show_promotions, show_discover_project_security: show_discover_project_security) }
subject { described_class.new(context) }
describe 'render?' do
context 'when user can access security and compliance' do
it 'returns true' do
expect(subject.render?).to eq true
end
end
context 'when user cannot access security and compliance' do
let(:user) { nil }
context 'when show discover project security is enabled' do
it 'returns true' do
expect(subject.render?).to eq true
end
end
context 'when show discover project security is disabled' do
let(:show_discover_project_security) { false }
it 'returns false' do
expect(subject.render?).to eq false
end
end
end
end
describe '#link' do
let(:show_promotions) { false }
using RSpec::Parameterized::TableSyntax
where(:security_dashboard_feature, :audit_events_feature, :dependency_scanning_feature, :expected_link) do
true | true | true | "/-/security/dashboard"
false | true | true | "/-/audit_events"
false | false | true | "/-/dependencies"
false | false | false | "/-/security/configuration"
end
with_them do
it 'returns the expected link' do
stub_licensed_features(security_dashboard: security_dashboard_feature, audit_events: audit_events_feature, dependency_scanning: dependency_scanning_feature)
expect(subject.link).to include(expected_link)
end
end
context 'when no security menu item and show promotions' do
let(:user) { nil }
it 'returns the link to the discover security path', :aggregate_failures do
expect(subject.items).to be_empty
expect(subject.link).to eq("/#{project.full_path}/-/security/discover")
end
end
end
describe 'Configuration' do
describe '#sidebar_security_configuration_paths' do
let(:expected_security_configuration_paths) do
%w[
projects/security/configuration#show
projects/security/sast_configuration#show
projects/security/api_fuzzing_configuration#show
projects/security/dast_profiles#show
projects/security/dast_site_profiles#new
projects/security/dast_site_profiles#edit
projects/security/dast_scanner_profiles#new
projects/security/dast_scanner_profiles#edit
]
end
subject { described_class.new(context).items.find { |i| i.item_id == :configuration } }
it 'includes all the security configuration paths' do
expect(subject.active_routes[:path]).to eq expected_security_configuration_paths
end
end
end
describe 'Security Dashboard' do
subject { described_class.new(context).items.find { |i| i.item_id == :dashboard } }
before do
stub_licensed_features(security_dashboard: true)
end
context 'when user can access security dashboard' do
it { is_expected.not_to be_nil }
end
context 'when user cannot access security dashboard' do
let(:user) { nil }
it { is_expected.to be_nil }
end
end
describe 'Vulnerability Report' do
subject { described_class.new(context).items.find { |i| i.item_id == :vulnerability_report } }
before do
stub_licensed_features(security_dashboard: true)
end
context 'when user can access vulnerabilities report' do
it { is_expected.not_to be_nil }
end
context 'when user cannot access vulnerabilities report' do
let(:user) { nil }
it { is_expected.to be_nil }
end
end
describe 'On Demand Scans' do
subject { described_class.new(context).items.find { |i| i.item_id == :on_demand_scans } }
before do
stub_licensed_features(security_on_demand_scans: true)
end
context 'when user can access vulnerabilities report' do
it { is_expected.not_to be_nil }
end
context 'when user cannot access vulnerabilities report' do
let(:user) { nil }
it { is_expected.to be_nil }
end
end
describe 'Dependency List' do
subject { described_class.new(context).items.find { |i| i.item_id == :dependency_list } }
before do
stub_licensed_features(dependency_scanning: true)
end
context 'when user can access dependency list' do
it { is_expected.not_to be_nil }
end
context 'when user cannot access dependency list' do
let(:user) { nil }
it { is_expected.to be_nil }
end
end
describe 'License Compliance' do
subject { described_class.new(context).items.find { |i| i.item_id == :license_compliance } }
before do
stub_licensed_features(license_scanning: true)
end
context 'when user can access license compliance' do
it { is_expected.not_to be_nil }
end
context 'when user cannot access license compliance' do
let(:user) { nil }
it { is_expected.to be_nil }
end
end
describe 'Threat monitoring' do
subject { described_class.new(context).items.find { |i| i.item_id == :threat_monitoring } }
before do
stub_licensed_features(threat_monitoring: true)
end
context 'when user can access threat monitoring' do
it { is_expected.not_to be_nil }
end
context 'when user cannot access threat monitoring' do
let(:user) { nil }
it { is_expected.to be_nil }
end
end
describe 'Scan Policies' do
subject { described_class.new(context).items.find { |i| i.item_id == :scan_policies } }
context 'when feature flag :security_orchestration_policies_configuration is enabled' do
before do
stub_feature_flags(security_orchestration_policies_configuration: true)
stub_licensed_features(security_orchestration_policies: true)
end
context 'when user can access scan policies' do
it { is_expected.not_to be_nil }
end
context 'when user cannot access scan policies' do
let(:user) { nil }
it { is_expected.to be_nil }
end
end
context 'when feature flag :security_orchestration_policies_configuration is disabled' do
before do
stub_feature_flags(security_orchestration_policies_configuration: false)
end
it { is_expected.to be_nil }
end
end
describe 'Audit Events' do
subject { described_class.new(context).items.find { |i| i.item_id == :audit_events } }
context 'when user can access audit events' do
it { is_expected.not_to be_nil }
context 'when feature audit events is licensed' do
before do
stub_licensed_features(audit_events: true)
end
it { is_expected.not_to be_nil }
end
context 'when feature audit events is not licensed' do
before do
stub_licensed_features(audit_events: false)
end
context 'when show promotions is enabled' do
it { is_expected.not_to be_nil }
end
context 'when show promotions is disabled' do
let(:show_promotions) { false }
it { is_expected.to be_nil }
end
end
end
context 'when user cannot access audit events' do
let(:user) { nil }
it { is_expected.to be_nil }
end
end
end
# frozen_string_literal: true
module Sidebars
module Projects
module Menus
class SecurityComplianceMenu < ::Sidebars::Menu
include Gitlab::Utils::StrongMemoize
override :configure_menu_items
def configure_menu_items
return false unless can?(context.current_user, :access_security_and_compliance, context.project)
add_item(configuration_menu_item)
true
end
override :link
def link
project_security_configuration_path(context.project)
end
override :title
def title
_('Security & Compliance')
end
override :sprite_icon
def sprite_icon
'shield'
end
private
def configuration_menu_item
strong_memoize(:configuration_menu_item) do
next unless render_configuration_menu_item?
::Sidebars::MenuItem.new(
title: _('Configuration'),
link: project_security_configuration_path(context.project),
active_routes: { path: configuration_menu_item_paths },
item_id: :configuration
)
end
end
def render_configuration_menu_item?
can?(context.current_user, :read_security_configuration, context.project)
end
def configuration_menu_item_paths
%w[
projects/security/configuration#show
]
end
end
end
end
end
Sidebars::Projects::Menus::SecurityComplianceMenu.prepend_if_ee('EE::Sidebars::Projects::Menus::SecurityComplianceMenu')
......@@ -15,6 +15,7 @@ module Sidebars
add_menu(Sidebars::Projects::Menus::LabelsMenu.new(context))
add_menu(Sidebars::Projects::Menus::MergeRequestsMenu.new(context))
add_menu(Sidebars::Projects::Menus::CiCdMenu.new(context))
add_menu(Sidebars::Projects::Menus::SecurityComplianceMenu.new(context))
end
override :render_raw_menus_partial
......
......@@ -8,26 +8,17 @@ module QA
module LicenseCompliance
extend QA::Page::PageConcern
def self.prepended(base)
base.class_eval do
view 'ee/app/views/layouts/nav/sidebar/_project_security_link.html.haml' do
element :licenses_list_link
element :security_dashboard_link
end
end
end
def click_on_license_compliance
hover_security_compliance do
within_submenu do
click_element(:licenses_list_link)
click_element(:sidebar_menu_item_link, menu_item: 'License Compliance')
end
end
end
def hover_security_compliance
within_sidebar do
find_element(:security_dashboard_link).hover
find_element(:sidebar_menu_link, menu_item: 'Security & Compliance').hover
yield
end
......
......@@ -8,27 +8,16 @@ module QA
module SecurityCompliance
extend QA::Page::PageConcern
def self.prepended(base)
base.class_eval do
view 'ee/app/views/layouts/nav/sidebar/_project_security_link.html.haml' do
element :security_dashboard_link
element :dependency_list_link
element :vulnerability_report_link
element :audit_events_settings_link
end
end
end
def click_on_security_dashboard
within_sidebar do
click_element :security_dashboard_link
click_element(:sidebar_menu_item_link, menu_item: 'Security Dashboard')
end
end
def click_on_dependency_list
hover_security_compliance do
within_submenu do
click_element(:dependency_list_link)
click_element(:sidebar_menu_item_link, menu_item: 'Dependency List')
end
end
end
......@@ -36,7 +25,7 @@ module QA
def click_on_vulnerability_report
hover_security_compliance do
within_submenu do
click_element(:vulnerability_report_link)
click_element(:sidebar_menu_item_link, menu_item: 'Vulnerability Report')
end
end
end
......@@ -44,14 +33,14 @@ module QA
def click_on_security_configuration_link
hover_security_compliance do
within_submenu do
click_element(:security_configuration_link)
click_element(:sidebar_menu_item_link, menu_item: 'Configuration')
end
end
end
def hover_security_compliance
within_sidebar do
find_element(:security_dashboard_link).hover
find_element(:sidebar_menu_link, menu_item: 'Security & Compliance').hover
yield
end
......@@ -60,7 +49,7 @@ module QA
def go_to_audit_events_settings
hover_security_compliance do
within_submenu do
click_element :audit_events_settings_link
click_element(:sidebar_menu_item_link, menu_item: 'Audit Events')
end
end
end
......
......@@ -400,25 +400,6 @@ RSpec.describe ProjectsHelper do
helper.send(:get_project_nav_tabs, project, user)
end
context 'Security & Compliance tabs' do
before do
allow(helper).to receive(:can?).with(user, :read_security_configuration, project).and_return(can_read_security_configuration)
end
context 'when user cannot read security configuration' do
let(:can_read_security_configuration) { false }
it { is_expected.not_to include(:security_configuration) }
end
context 'when user can read security configuration' do
let(:can_read_security_configuration) { true }
let(:feature_flag_enabled) { true }
it { is_expected.to include(:security_configuration) }
end
end
context 'when builds feature is enabled' do
before do
allow(project).to receive(:builds_enabled?).and_return(true)
......
......@@ -315,6 +315,36 @@ RSpec.describe 'layouts/nav/sidebar/_project' do
end
end
describe 'Security and Compliance' do
describe 'when user does not have permissions' do
before do
allow(view).to receive(:current_user).and_return(nil)
end
it 'top level navigation link is not visible' do
render
expect(rendered).not_to have_link('Security & Compliance')
end
end
context 'when user has permissions' do
before do
allow(view).to receive(:current_user).and_return(user)
render
end
it 'top level navigation link is visible' do
expect(rendered).to have_link('Security & Compliance')
end
it 'security configuration link is visible' do
expect(rendered).to have_link('Configuration', href: project_security_configuration_path(project))
end
end
end
describe 'packages tab' do
before do
stub_container_registry_config(enabled: true)
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe 'layouts/nav/sidebar/_project_security_link' do
let_it_be_with_reload(:project) { create(:project) }
context 'on security configuration' do
before do
assign(:project, project)
allow(controller).to receive(:controller_name).and_return('configuration')
allow(controller).to receive(:controller_path).and_return('projects/security/configuration')
allow(controller).to receive(:action_name).and_return('show')
allow(view).to receive(:any_project_nav_tab?).and_return(true)
allow(view).to receive(:project_nav_tab?).and_return(true)
end
it 'activates Security & Compliance tab' do
render
expect(rendered).to have_css('li.active', text: 'Security & Compliance')
end
it 'activates Configuration sub tab' do
render
expect(rendered).to have_css('.sidebar-sub-level-items > li.active', text: 'Configuration')
end
end
end
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