diff --git a/ee/app/controllers/security/application_controller.rb b/ee/app/controllers/security/application_controller.rb new file mode 100644 index 0000000000000000000000000000000000000000..ebab1169bf15ad9464f419770e631c3da0d528d0 --- /dev/null +++ b/ee/app/controllers/security/application_controller.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +module Security + class ApplicationController < ::ApplicationController + before_action :authorize_read_security_dashboard! + before_action do + push_frontend_feature_flag(:security_dashboard) + end + + private + + def authorize_read_security_dashboard! + render_404 unless Feature.enabled?(:security_dashboard) && + can?(current_user, :read_security_dashboard) + end + end +end diff --git a/ee/app/controllers/security/dashboard_controller.rb b/ee/app/controllers/security/dashboard_controller.rb new file mode 100644 index 0000000000000000000000000000000000000000..0c3bbbd0772079f25077e867f1f379474e032486 --- /dev/null +++ b/ee/app/controllers/security/dashboard_controller.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +module Security + class DashboardController < ::Security::ApplicationController + def show + head :ok + end + end +end diff --git a/ee/app/controllers/security/projects_controller.rb b/ee/app/controllers/security/projects_controller.rb new file mode 100644 index 0000000000000000000000000000000000000000..7147453a080aa47122f4c4733dc1fec43e4b8e4d --- /dev/null +++ b/ee/app/controllers/security/projects_controller.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +module Security + class ProjectsController < ::Security::ApplicationController + def index + head :ok + end + + def create + head :ok + end + + def destroy + head :ok + end + end +end diff --git a/ee/app/controllers/security_controller.rb b/ee/app/controllers/security_controller.rb deleted file mode 100644 index 95911c696c02f9b319074da241bbfb70ba2fd20a..0000000000000000000000000000000000000000 --- a/ee/app/controllers/security_controller.rb +++ /dev/null @@ -1,13 +0,0 @@ -# frozen_string_literal: true - -class SecurityController < ApplicationController - before_action :authorize_read_security_dashboard! - before_action do - push_frontend_feature_flag(:security_dashboard) - end - - def authorize_read_security_dashboard! - render_404 unless Feature.enabled?(:security_dashboard) && - can?(current_user, :read_security_dashboard) - end -end diff --git a/ee/app/policies/ee/global_policy.rb b/ee/app/policies/ee/global_policy.rb index 116478f4b29580fc1560e896d03ffe0ce23b021f..deaaeaab42e4a0fda78f91ff3979564c685b25fe 100644 --- a/ee/app/policies/ee/global_policy.rb +++ b/ee/app/policies/ee/global_policy.rb @@ -9,7 +9,13 @@ module GlobalPolicy License.feature_available?(:operations_dashboard) end + condition(:security_dashboard_available) do + License.feature_available?(:security_dashboard) + end + rule { operations_dashboard_available }.enable :read_operations_dashboard + rule { ~anonymous & security_dashboard_available }.enable :read_security_dashboard + rule { admin }.policy do enable :read_licenses enable :destroy_licenses diff --git a/ee/app/views/dashboard/_nav_link_list.html.haml b/ee/app/views/dashboard/_nav_link_list.html.haml index f9bf02a9d2470a6fc1381344beab896406acf46b..135987ac8b6ca1b8ebbd536d0f61fd010b89b195 100644 --- a/ee/app/views/dashboard/_nav_link_list.html.haml +++ b/ee/app/views/dashboard/_nav_link_list.html.haml @@ -5,5 +5,5 @@ = link_to operations_path, class: 'dropdown-item' do = _('Operations') - if dashboard_nav_link?(:security) - = link_to security_path, class: 'dropdown-item' do + = link_to security_root_path, class: 'dropdown-item' do = _('Security') diff --git a/ee/config/routes/security.rb b/ee/config/routes/security.rb index c5a263bd95f5e44e7b68b5d5c7d65eb967bab4ea..af565a20ccb939c99ef0d965021cfec0df8b2ad5 100644 --- a/ee/config/routes/security.rb +++ b/ee/config/routes/security.rb @@ -1,3 +1,7 @@ # frozen_string_literal: true -get 'security' => 'security#index' +namespace :security do + root to: 'dashboard#show' + + resources :projects, only: [:index, :create, :destroy] +end diff --git a/ee/spec/controllers/security/dashboard_controller_spec.rb b/ee/spec/controllers/security/dashboard_controller_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..a4252a91e8504fe15e53a350ca942b3b2c452c44 --- /dev/null +++ b/ee/spec/controllers/security/dashboard_controller_spec.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Security::DashboardController do + describe 'GET #show' do + it_behaves_like Security::ApplicationController do + let(:security_application_controller_child_action) do + get :show + end + end + end +end diff --git a/ee/spec/controllers/security/projects_controller_spec.rb b/ee/spec/controllers/security/projects_controller_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..ae4e915db3db9cff86f2eaeb25a9aa69d334ee4b --- /dev/null +++ b/ee/spec/controllers/security/projects_controller_spec.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Security::ProjectsController do + describe 'GET #index' do + it_behaves_like Security::ApplicationController do + let(:security_application_controller_child_action) do + get :index + end + end + end + + describe 'POST #create' do + it_behaves_like Security::ApplicationController do + let(:security_application_controller_child_action) do + post :create + end + end + end + + describe 'DELETE #destroy' do + it_behaves_like Security::ApplicationController do + let(:security_application_controller_child_action) do + delete :destroy, params: { id: 1 } + end + end + end +end diff --git a/ee/spec/policies/global_policy_spec.rb b/ee/spec/policies/global_policy_spec.rb index ca11d3fdd60a15f25566e95bc72d1b30b202e282..09bf765cf42b40b5ae07fa3981bc9da5e611b11e 100644 --- a/ee/spec/policies/global_policy_spec.rb +++ b/ee/spec/policies/global_policy_spec.rb @@ -55,4 +55,30 @@ describe 'view_productivity_analytics' do include_examples 'analytics policy', :view_productivity_analytics end + + describe 'read_security_dashboard' do + context 'when the instance has an Ultimate license' do + before do + stub_licensed_features(security_dashboard: true) + end + + context 'and the user is not logged in' do + let(:current_user) { nil } + + it { is_expected.not_to be_allowed(:read_security_dashboard) } + end + + context 'and the user is logged in' do + it { is_expected.to be_allowed(:read_security_dashboard) } + end + end + + context 'when the instance does not have an Ultimate license' do + before do + stub_licensed_features(security_dashboard: false) + end + + it { is_expected.not_to be_allowed(:read_security_dashboard) } + end + end end diff --git a/ee/spec/support/shared_examples/controllers/security/application_controller_shared_examples.rb b/ee/spec/support/shared_examples/controllers/security/application_controller_shared_examples.rb new file mode 100644 index 0000000000000000000000000000000000000000..1a88d9086abcecfc7083f802233d3dbbd19ccac5 --- /dev/null +++ b/ee/spec/support/shared_examples/controllers/security/application_controller_shared_examples.rb @@ -0,0 +1,48 @@ +# frozen_string_literal: true + +require 'spec_helper' + +shared_examples Security::ApplicationController do + context 'when the user is authenticated' do + let(:security_application_controller_user) { create(:user) } + + before do + stub_licensed_features(security_dashboard: true) + sign_in(security_application_controller_user) + end + + it 'responds with success' do + security_application_controller_child_action + + expect(response).to have_gitlab_http_status(:ok) + end + + context 'and the instance does not have an Ultimate license' do + it '404s' do + stub_licensed_features(security_dashboard: false) + + security_application_controller_child_action + + expect(response).to have_gitlab_http_status(:not_found) + end + end + + context 'and the security dashboard feature is disabled' do + it '404s' do + stub_feature_flags(security_dashboard: false) + + security_application_controller_child_action + + expect(response).to have_gitlab_http_status(:not_found) + end + end + end + + context 'when the user is not authenticated' do + it 'redirects the user to the sign in page' do + security_application_controller_child_action + + expect(response).to redirect_to(new_user_session_path) + end + end +end