Commit dc6f1ca9 authored by Stan Hu's avatar Stan Hu

Merge branch '17969-isd-vulnerable-projects' into 'master'

Add projects widget to instance security dashboard

See merge request gitlab-org/gitlab!24644
parents 33816707 df4c29d0
......@@ -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.
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
bar at the top of the page. Under **More**, select **Security**.
......@@ -133,7 +134,7 @@ To add projects to the dashboard:
Once added, the dashboard will display the vulnerabilities found in your chosen
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
......
# 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 @@
module Security
class VulnerableProjectsFinder
PROJECTS_LIMIT = 5000
def initialize(projects)
@projects = projects
end
def execute
projects.where("EXISTS(?)", vulnerabilities) # rubocop:disable CodeReuse/ActiveRecord
projects.where("EXISTS(?)", vulnerabilities).limit(PROJECTS_LIMIT) # rubocop:disable CodeReuse/ActiveRecord
end
private
......
......@@ -8,6 +8,7 @@ module SecurityHelper
empty_state_svg_path: image_path('illustrations/operations-dashboard_empty.svg'),
project_add_endpoint: security_projects_path,
project_list_endpoint: security_projects_path,
vulnerable_projects_endpoint: security_vulnerable_projects_path,
vulnerabilities_endpoint: 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')
......
......@@ -25,6 +25,10 @@ class InstanceSecurityDashboard
License.feature_available?(feature)
end
def projects
Project.where(id: visible_users_security_dashboard_projects)
end
private
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
root to: 'dashboard#show'
resources :projects, only: [:index, :create, :destroy]
resources :vulnerable_projects, only: [:index]
resources :vulnerability_findings, only: [:index] do
collection do
......
......@@ -17,6 +17,7 @@ describe SecurityHelper do
empty_state_svg_path: image_path('illustrations/operations-dashboard_empty.svg'),
project_add_endpoint: security_projects_path,
project_list_endpoint: security_projects_path,
vulnerable_projects_endpoint: security_vulnerable_projects_path,
vulnerabilities_endpoint: 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')
......
......@@ -89,4 +89,21 @@ describe InstanceSecurityDashboard do
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
# 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