Commit d702f940 authored by Mark Florian's avatar Mark Florian Committed by Dmitriy Zaporozhets

Add Threat Monitoring skeleton page

Part of [WAF statistics reporting][1].

This adds:

- A skeleton page and sidebar nav link for WAF statistics reporting
- `threat_monitoring` GitLab Ultimate feature
- `threat_monitoring` feature flag (disabled by default)
- Additional unit tests for the EE projects helper

[1]: https://gitlab.com/gitlab-org/gitlab/issues/14707
parent 71da2ba2
# frozen_string_literal: true
module Projects
class ThreatMonitoringController < Projects::ApplicationController
before_action :authorize_read_threat_monitoring!
before_action only: [:show] do
push_frontend_feature_flag(:threat_monitoring)
end
end
end
...@@ -49,6 +49,10 @@ module EE ...@@ -49,6 +49,10 @@ module EE
nav_tabs << :licenses nav_tabs << :licenses
end end
if can?(current_user, :read_threat_monitoring, project)
nav_tabs << :threat_monitoring
end
if ::Gitlab.config.packages.enabled && if ::Gitlab.config.packages.enabled &&
project.feature_available?(:packages) && project.feature_available?(:packages) &&
can?(current_user, :read_package, project) can?(current_user, :read_package, project)
...@@ -145,6 +149,7 @@ module EE ...@@ -145,6 +149,7 @@ module EE
projects/security/dashboard#show projects/security/dashboard#show
projects/dependencies#show projects/dependencies#show
projects/licenses#show projects/licenses#show
projects/threat_monitoring#show
] ]
end end
......
...@@ -120,6 +120,7 @@ class License < ApplicationRecord ...@@ -120,6 +120,7 @@ class License < ApplicationRecord
report_approver_rules report_approver_rules
sast sast
security_dashboard security_dashboard
threat_monitoring
tracing tracing
web_ide_terminal web_ide_terminal
] ]
......
...@@ -80,6 +80,11 @@ module EE ...@@ -80,6 +80,11 @@ module EE
@subject.feature_available?(:dependency_scanning) @subject.feature_available?(:dependency_scanning)
end end
with_scope :subject
condition(:threat_monitoring_enabled) do
@subject.beta_feature_available?(:threat_monitoring)
end
with_scope :subject with_scope :subject
condition(:feature_flags_disabled) do condition(:feature_flags_disabled) do
!@subject.feature_available?(:feature_flags) !@subject.feature_available?(:feature_flags)
...@@ -168,6 +173,8 @@ module EE ...@@ -168,6 +173,8 @@ module EE
enable :admin_vulnerability enable :admin_vulnerability
end end
rule { threat_monitoring_enabled & (auditor | can?(:developer_access)) }.enable :read_threat_monitoring
rule { can?(:read_project) & (can?(:read_merge_request) | can?(:read_build)) }.enable :read_vulnerability_feedback rule { can?(:read_project) & (can?(:read_merge_request) | can?(:read_build)) }.enable :read_vulnerability_feedback
rule { dependency_scanning_enabled & can?(:download_code) }.enable :read_dependencies rule { dependency_scanning_enabled & can?(:download_code) }.enable :read_dependencies
......
...@@ -37,3 +37,8 @@ ...@@ -37,3 +37,8 @@
= nav_link(path: 'projects/security/configuration#show') do = nav_link(path: 'projects/security/configuration#show') do
= 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?(:threat_monitoring)
= nav_link(path: 'projects/threat_monitoring#show') do
= link_to project_threat_monitoring_path(@project), title: _('Threat Monitoring') do
%span= _('Threat Monitoring')
- breadcrumb_title _("Threat Monitoring")
- page_title _("Threat Monitoring")
#js-threat-monitoring-app
...@@ -70,6 +70,8 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do ...@@ -70,6 +70,8 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
resources :licenses, only: [:index, :create, :update] resources :licenses, only: [:index, :create, :update]
end end
resource :threat_monitoring, only: [:show], controller: :threat_monitoring
resources :logs, only: [:index] do resources :logs, only: [:index] do
collection do collection do
get :k8s get :k8s
......
# frozen_string_literal: true
require 'spec_helper'
describe Projects::ThreatMonitoringController do
set(:project) { create(:project, :repository, :private) }
set(:user) { create(:user) }
subject { get :show, params: { namespace_id: project.namespace, project_id: project } }
describe 'GET show' do
context 'with authorized user' do
before do
project.add_developer(user)
sign_in(user)
end
context 'when feature is available' do
before do
stub_licensed_features(threat_monitoring: true)
end
it 'renders the show template' do
subject
expect(response).to have_gitlab_http_status(200)
expect(response).to render_template(:show)
end
end
context 'when feature is not available' do
before do
stub_feature_flags(threat_monitoring: false)
stub_licensed_features(threat_monitoring: false)
end
it 'returns 404' do
subject
expect(response).to have_gitlab_http_status(404)
end
end
end
context 'with unauthorized user' do
before do
sign_in(user)
end
context 'when feature is available' do
before do
stub_licensed_features(threat_monitoring: true)
end
it 'returns 404' do
subject
expect(response).to have_gitlab_http_status(404)
end
end
end
context 'with anonymous user' do
it 'returns 302' do
subject
expect(response).to have_gitlab_http_status(302)
expect(response).to redirect_to(new_user_session_path)
end
end
end
end
...@@ -155,4 +155,49 @@ describe ProjectsHelper do ...@@ -155,4 +155,49 @@ describe ProjectsHelper do
end end
end end
end end
describe '#get_project_nav_tabs' do
using RSpec::Parameterized::TableSyntax
where(:ability, :nav_tab) do
:read_dependencies | :dependencies
:read_feature_flag | :operations
:read_licenses | :licenses
:read_project_security_dashboard | :security
:read_threat_monitoring | :threat_monitoring
end
with_them do
let(:project) { create(:project) }
let(:user) { create(:user) }
before do
allow(helper).to receive(:can?) { false }
end
subject do
helper.send(:get_project_nav_tabs, project, user)
end
context 'when the feature is disabled' do
before do
allow(helper).to receive(:can?).with(user, ability, project).and_return(false)
end
it 'does not include the nav tab' do
is_expected.not_to include(nav_tab)
end
end
context 'when threat monitoring is enabled' do
before do
allow(helper).to receive(:can?).with(user, ability, project).and_return(true)
end
it 'includes the nav tab' do
is_expected.to include(nav_tab)
end
end
end
end
end end
...@@ -50,6 +50,7 @@ describe ProjectPolicy do ...@@ -50,6 +50,7 @@ describe ProjectPolicy do
create_merge_request_in award_emoji create_merge_request_in award_emoji
read_project_security_dashboard read_vulnerability read_project_security_dashboard read_vulnerability
read_vulnerability_feedback read_security_findings read_software_license_policy read_vulnerability_feedback read_security_findings read_software_license_policy
read_threat_monitoring
] ]
end end
...@@ -65,7 +66,7 @@ describe ProjectPolicy do ...@@ -65,7 +66,7 @@ describe ProjectPolicy do
let(:current_user) { create(:user, :auditor) } let(:current_user) { create(:user, :auditor) }
before do before do
stub_licensed_features(security_dashboard: true, license_management: true) stub_licensed_features(security_dashboard: true, license_management: true, threat_monitoring: true)
end end
context 'who is not a team member' do context 'who is not a team member' do
...@@ -550,6 +551,58 @@ describe ProjectPolicy do ...@@ -550,6 +551,58 @@ describe ProjectPolicy do
end end
end end
describe 'read_threat_monitoring' do
context 'when threat monitoring feature is available' do
before do
stub_feature_flags(threat_monitoring: true)
stub_licensed_features(threat_monitoring: true)
end
context 'with developer or higher role' do
where(role: %w[admin owner maintainer developer])
with_them do
let(:current_user) { public_send(role) }
it { is_expected.to be_allowed(:read_threat_monitoring) }
end
end
context 'with less than developer role' do
where(role: %w[reporter guest])
with_them do
let(:current_user) { public_send(role) }
it { is_expected.to be_disallowed(:read_threat_monitoring) }
end
end
context 'with not member' do
let(:current_user) { create(:user) }
it { is_expected.to be_disallowed(:read_threat_monitoring) }
end
context 'with anonymous' do
let(:current_user) { nil }
it { is_expected.to be_disallowed(:read_threat_monitoring) }
end
end
context 'when threat monitoring feature is not available' do
let(:current_user) { admin }
before do
stub_feature_flags(threat_monitoring: false)
stub_licensed_features(threat_monitoring: false)
end
it { is_expected.to be_disallowed(:read_threat_monitoring) }
end
end
describe 'read_package' do describe 'read_package' do
context 'with admin' do context 'with admin' do
let(:current_user) { admin } let(:current_user) { admin }
......
...@@ -18254,6 +18254,9 @@ msgstr "" ...@@ -18254,6 +18254,9 @@ msgstr ""
msgid "Those emails automatically become issues (with the comments becoming the email conversation) listed here." msgid "Those emails automatically become issues (with the comments becoming the email conversation) listed here."
msgstr "" msgstr ""
msgid "Threat Monitoring"
msgstr ""
msgid "Thursday" msgid "Thursday"
msgstr "" msgstr ""
......
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