Commit df4c29d0 authored by Avielle Wolfe's avatar Avielle Wolfe Committed by Stan Hu

Add vuln projs widget to instance sec dashboard

Adds Security::VulnerableProjectsController and accompanying route,
which reuses the logic backing the vulnerable projects widget on the
group security dashboard.

https://gitlab.com/gitlab-org/gitlab/issues/17969
parent 8301bed3
...@@ -115,7 +115,8 @@ Read more on how to [interact with the vulnerabilities](../index.md#interacting- ...@@ -115,7 +115,8 @@ Read more on how to [interact with the vulnerabilities](../index.md#interacting-
> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/6953) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 12.8. > [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/6953) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 12.8.
At the instance level, the Security Dashboard displays the vulnerabilities At the instance level, the Security Dashboard displays the vulnerabilities
present in all of the projects that you have added to it. present in all of the projects that you have added to it. It includes all
of the features of the [group security dashboard](#group-security-dashboard).
You can access the Instance Security Dashboard from the menu You can access the Instance Security Dashboard from the menu
bar at the top of the page. Under **More**, select **Security**. bar at the top of the page. Under **More**, select **Security**.
...@@ -133,7 +134,7 @@ To add projects to the dashboard: ...@@ -133,7 +134,7 @@ To add projects to the dashboard:
Once added, the dashboard will display the vulnerabilities found in your chosen Once added, the dashboard will display the vulnerabilities found in your chosen
projects. projects.
![Instance Security Dashboard with projects](img/instance_security_dashboard_with_projects_v12_7.png) ![Instance Security Dashboard with projects](img/instance_security_dashboard_with_projects_v12_8.png)
## Keeping the dashboards up to date ## Keeping the dashboards up to date
......
# frozen_string_literal: true
class Security::VulnerableProjectsController < Security::ApplicationController
def index
vulnerable_projects = ::Security::VulnerableProjectsFinder.new(projects).execute
presented_projects = vulnerable_projects.map do |project|
::Security::VulnerableProjectPresenter.new(project)
end
render json: VulnerableProjectSerializer.new.represent(presented_projects)
end
private
def projects
vulnerable.projects.non_archived.without_deleted.with_route
end
end
...@@ -2,12 +2,14 @@ ...@@ -2,12 +2,14 @@
module Security module Security
class VulnerableProjectsFinder class VulnerableProjectsFinder
PROJECTS_LIMIT = 5000
def initialize(projects) def initialize(projects)
@projects = projects @projects = projects
end end
def execute def execute
projects.where("EXISTS(?)", vulnerabilities) # rubocop:disable CodeReuse/ActiveRecord projects.where("EXISTS(?)", vulnerabilities).limit(PROJECTS_LIMIT) # rubocop:disable CodeReuse/ActiveRecord
end end
private private
......
...@@ -8,6 +8,7 @@ module SecurityHelper ...@@ -8,6 +8,7 @@ module SecurityHelper
empty_state_svg_path: image_path('illustrations/operations-dashboard_empty.svg'), empty_state_svg_path: image_path('illustrations/operations-dashboard_empty.svg'),
project_add_endpoint: security_projects_path, project_add_endpoint: security_projects_path,
project_list_endpoint: security_projects_path, project_list_endpoint: security_projects_path,
vulnerable_projects_endpoint: security_vulnerable_projects_path,
vulnerabilities_endpoint: security_vulnerability_findings_path, vulnerabilities_endpoint: security_vulnerability_findings_path,
vulnerabilities_history_endpoint: history_security_vulnerability_findings_path, vulnerabilities_history_endpoint: history_security_vulnerability_findings_path,
vulnerability_feedback_help_path: help_page_path('user/application_security/index', anchor: 'interacting-with-the-vulnerabilities') vulnerability_feedback_help_path: help_page_path('user/application_security/index', anchor: 'interacting-with-the-vulnerabilities')
......
...@@ -25,6 +25,10 @@ class InstanceSecurityDashboard ...@@ -25,6 +25,10 @@ class InstanceSecurityDashboard
License.feature_available?(feature) License.feature_available?(feature)
end end
def projects
Project.where(id: visible_users_security_dashboard_projects)
end
private private
attr_reader :project_ids, :user attr_reader :project_ids, :user
......
---
title: Add affected projects feature to instance security dashboard
merge_request: 24644
author:
type: added
...@@ -4,6 +4,7 @@ namespace :security do ...@@ -4,6 +4,7 @@ namespace :security do
root to: 'dashboard#show' root to: 'dashboard#show'
resources :projects, only: [:index, :create, :destroy] resources :projects, only: [:index, :create, :destroy]
resources :vulnerable_projects, only: [:index]
resources :vulnerability_findings, only: [:index] do resources :vulnerability_findings, only: [:index] do
collection do collection do
......
...@@ -17,6 +17,7 @@ describe SecurityHelper do ...@@ -17,6 +17,7 @@ describe SecurityHelper do
empty_state_svg_path: image_path('illustrations/operations-dashboard_empty.svg'), empty_state_svg_path: image_path('illustrations/operations-dashboard_empty.svg'),
project_add_endpoint: security_projects_path, project_add_endpoint: security_projects_path,
project_list_endpoint: security_projects_path, project_list_endpoint: security_projects_path,
vulnerable_projects_endpoint: security_vulnerable_projects_path,
vulnerabilities_endpoint: security_vulnerability_findings_path, vulnerabilities_endpoint: security_vulnerability_findings_path,
vulnerabilities_history_endpoint: history_security_vulnerability_findings_path, vulnerabilities_history_endpoint: history_security_vulnerability_findings_path,
vulnerability_feedback_help_path: help_page_path('user/application_security/index', anchor: 'interacting-with-the-vulnerabilities') vulnerability_feedback_help_path: help_page_path('user/application_security/index', anchor: 'interacting-with-the-vulnerabilities')
......
...@@ -89,4 +89,21 @@ describe InstanceSecurityDashboard do ...@@ -89,4 +89,21 @@ describe InstanceSecurityDashboard do
end end
end end
end end
describe '#projects' do
context 'when the user cannot read all resources' do
it 'returns only projects on their dashboard that they can read' do
expect(subject.projects).to contain_exactly(project1)
end
end
context 'when the user can read all resources' do
let(:project_ids) { [project1.id, project2.id] }
let(:user) { create(:auditor) }
it "returns all projects on the user's dashboard" do
expect(subject.projects).to contain_exactly(project1, project2)
end
end
end
end end
# frozen_string_literal: true
require 'spec_helper'
describe 'GET /-/security/vulnerable_projects' do
it_behaves_like 'security dashboard JSON endpoint' do
let(:security_dashboard_request) do
get security_vulnerable_projects_path, headers: { 'ACCEPT' => 'application/json' }
end
end
context 'with an authenticated user' do
let(:project) { create(:project) }
let(:user) { create(:user) }
before do
stub_licensed_features(security_dashboard: true)
project.add_developer(user)
user.security_dashboard_projects << project
login_as(user)
end
subject { get security_vulnerable_projects_path, headers: { 'ACCEPT' => 'application/json' } }
it "responds with the projects on the user's dashboard and their vulnerability counts" do
safe_project = create(:project)
safe_project.add_developer(user)
user.security_dashboard_projects << safe_project
pipeline = create(:ci_pipeline, :success, project: project)
create_list(
:vulnerabilities_occurrence,
2,
pipelines: [pipeline],
project: project,
severity: :critical
)
subject
expect(response).to have_gitlab_http_status(:ok)
expect(json_response.count).to be(1)
expect(json_response.first['id']).to eq(project.id)
expect(json_response.first['full_path']).to eq(project_path(project))
expect(json_response.first['critical_vulnerability_count']).to eq(2)
end
it 'does not include archived or deleted projects' do
archived_project = create(:project, :archived)
deleted_project = create(:project, pending_delete: true)
archived_pipeline = create(:ci_pipeline, :success, project: archived_project)
deleted_pipeline = create(:ci_pipeline, :success, project: deleted_project)
create(:vulnerabilities_occurrence, pipelines: [archived_pipeline], project: archived_project)
create(:vulnerabilities_occurrence, pipelines: [deleted_pipeline], project: deleted_project)
archived_project.add_developer(user)
deleted_project.add_developer(user)
user.security_dashboard_projects << [archived_project, deleted_project]
subject
expect(response).to have_gitlab_http_status(:ok)
expect(json_response).to be_empty
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