Commit fa89ae71 authored by Victor Zagorodny's avatar Victor Zagorodny Committed by Lin Jen-Shin

Get single Vulnerability API call

parent f29f4487
...@@ -13,9 +13,14 @@ module API ...@@ -13,9 +13,14 @@ module API
Vulnerability.with_findings.find(params[:id]) Vulnerability.with_findings.find(params[:id])
end end
def authorize_vulnerability!(vulnerability, action)
authorize! action, vulnerability.project
vulnerability
end
def find_and_authorize_vulnerability!(action) def find_and_authorize_vulnerability!(action)
find_vulnerability!.tap do |vulnerability| find_vulnerability!.tap do |vulnerability|
authorize! action, vulnerability.project authorize_vulnerability!(vulnerability, action)
end end
end end
...@@ -38,6 +43,15 @@ module API ...@@ -38,6 +43,15 @@ module API
requires :id, type: String, desc: 'The ID of a vulnerability' requires :id, type: String, desc: 'The ID of a vulnerability'
end end
resource :vulnerabilities do resource :vulnerabilities do
desc 'Get a vulnerability' do
success VulnerabilityEntity
end
get ':id' do
vulnerability = Vulnerability.find(params[:id])
authorize_vulnerability!(vulnerability, :read_project_security_dashboard)
render_vulnerability(vulnerability)
end
desc 'Resolve a vulnerability' do desc 'Resolve a vulnerability' do
success VulnerabilityEntity success VulnerabilityEntity
end end
......
...@@ -9,6 +9,8 @@ describe API::Vulnerabilities do ...@@ -9,6 +9,8 @@ describe API::Vulnerabilities do
let_it_be(:project) { create(:project, :with_vulnerabilities) } let_it_be(:project) { create(:project, :with_vulnerabilities) }
let_it_be(:user) { create(:user) } let_it_be(:user) { create(:user) }
let_it_be(:vulnerability) { project.vulnerabilities.first }
let(:vulnerability_id) { vulnerability.id }
shared_examples 'forbids actions on vulnerability in case of disabled features' do shared_examples 'forbids actions on vulnerability in case of disabled features' do
context 'when "first-class vulnerabilities" feature is disabled' do context 'when "first-class vulnerabilities" feature is disabled' do
...@@ -36,10 +38,20 @@ describe API::Vulnerabilities do ...@@ -36,10 +38,20 @@ describe API::Vulnerabilities do
end end
end end
shared_examples 'responds with "not found" for an unknown vulnerability ID' do
let(:vulnerability_id) { 0 }
it do
subject
expect(response).to have_gitlab_http_status(404)
end
end
describe 'GET /projects/:id/vulnerabilities' do describe 'GET /projects/:id/vulnerabilities' do
let(:project_vulnerabilities_path) { "/projects/#{project.id}/vulnerabilities" } let(:project_vulnerabilities_path) { "/projects/#{project.id}/vulnerabilities" }
subject { get api(project_vulnerabilities_path, user) } subject(:get_vulnerabilities) { get api(project_vulnerabilities_path, user) }
context 'with an authorized user with proper permissions' do context 'with an authorized user with proper permissions' do
before do before do
...@@ -47,7 +59,7 @@ describe API::Vulnerabilities do ...@@ -47,7 +59,7 @@ describe API::Vulnerabilities do
end end
it 'returns all vulnerabilities of a project' do it 'returns all vulnerabilities of a project' do
subject get_vulnerabilities
expect(response).to have_gitlab_http_status(200) expect(response).to have_gitlab_http_status(200)
expect(response).to include_pagination_headers expect(response).to include_pagination_headers
...@@ -59,7 +71,7 @@ describe API::Vulnerabilities do ...@@ -59,7 +71,7 @@ describe API::Vulnerabilities do
let(:project_vulnerabilities_path) { "#{super()}?page=2&per_page=1" } let(:project_vulnerabilities_path) { "#{super()}?page=2&per_page=1" }
it 'paginates the vulnerabilities according to the pagination params' do it 'paginates the vulnerabilities according to the pagination params' do
subject get_vulnerabilities
expect(response).to have_gitlab_http_status(200) expect(response).to have_gitlab_http_status(200)
expect(json_response.map { |v| v['id'] }).to contain_exactly(project.vulnerabilities.second.id) expect(json_response.map { |v| v['id'] }).to contain_exactly(project.vulnerabilities.second.id)
...@@ -70,17 +82,47 @@ describe API::Vulnerabilities do ...@@ -70,17 +82,47 @@ describe API::Vulnerabilities do
end end
it_behaves_like 'responds with "not found" when there is no access to the project' it_behaves_like 'responds with "not found" when there is no access to the project'
it_behaves_like 'prevents working with vulnerabilities in case of insufficient privileges' it_behaves_like 'prevents working with vulnerabilities in case of insufficient access level'
end end
describe "POST /vulnerabilities:id/dismiss" do shared_examples 'prevents working with vulnerabilities for anonymous users' do
it do
subject
expect(response).to have_gitlab_http_status(403)
end
end
describe 'GET /vulnerabilities/:id' do
subject(:get_vulnerability) { get api("/vulnerabilities/#{vulnerability_id}", user) }
context 'with an authorized user with proper permissions' do
before do
project.add_developer(user)
end
it 'returns the desired vulnerability' do
get_vulnerability
expect(response).to have_gitlab_http_status(200)
expect(response).to match_response_schema('vulnerability', dir: 'ee')
expect(json_response['id']).to eq vulnerability_id
end
it_behaves_like 'responds with "not found" for an unknown vulnerability ID'
it_behaves_like 'forbids actions on vulnerability in case of disabled features'
end
it_behaves_like 'prevents working with vulnerabilities in case of insufficient access level'
it_behaves_like 'prevents working with vulnerabilities for anonymous users'
end
describe 'POST /vulnerabilities/:id/dismiss' do
before do before do
create_list(:vulnerabilities_occurrence, 2, vulnerability: vulnerability, project: vulnerability.project) create_list(:vulnerabilities_occurrence, 2, vulnerability: vulnerability, project: vulnerability.project)
end end
let(:vulnerability) { project.vulnerabilities.first } subject(:dismiss_vulnerability) { post api("/vulnerabilities/#{vulnerability_id}/dismiss", user) }
subject { post api("/vulnerabilities/#{vulnerability.id}/dismiss", user) }
context 'with an authorized user with proper permissions' do context 'with an authorized user with proper permissions' do
before do before do
...@@ -89,7 +131,7 @@ describe API::Vulnerabilities do ...@@ -89,7 +131,7 @@ describe API::Vulnerabilities do
it 'dismisses a vulnerability and its associated findings' do it 'dismisses a vulnerability and its associated findings' do
Timecop.freeze do Timecop.freeze do
subject dismiss_vulnerability
expect(response).to have_gitlab_http_status(201) expect(response).to have_gitlab_http_status(201)
expect(response).to match_response_schema('vulnerability', dir: 'ee') expect(response).to match_response_schema('vulnerability', dir: 'ee')
...@@ -100,6 +142,8 @@ describe API::Vulnerabilities do ...@@ -100,6 +142,8 @@ describe API::Vulnerabilities do
end end
end end
it_behaves_like 'responds with "not found" for an unknown vulnerability ID'
context 'when there is a dismissal error' do context 'when there is a dismissal error' do
before do before do
Grape::Endpoint.before_each do |endpoint| Grape::Endpoint.before_each do |endpoint|
...@@ -123,7 +167,7 @@ describe API::Vulnerabilities do ...@@ -123,7 +167,7 @@ describe API::Vulnerabilities do
end end
it 'responds with error' do it 'responds with error' do
subject dismiss_vulnerability
expect(response).to have_gitlab_http_status(400) expect(response).to have_gitlab_http_status(400)
expect(json_response['message']).to eq('base' => ['something went wrong']) expect(json_response['message']).to eq('base' => ['something went wrong'])
...@@ -134,7 +178,7 @@ describe API::Vulnerabilities do ...@@ -134,7 +178,7 @@ describe API::Vulnerabilities do
let(:vulnerability) { create(:vulnerability, :closed, project: project) } let(:vulnerability) { create(:vulnerability, :closed, project: project) }
it 'responds with 304 Not Modified' do it 'responds with 304 Not Modified' do
subject dismiss_vulnerability
expect(response).to have_gitlab_http_status(304) expect(response).to have_gitlab_http_status(304)
end end
...@@ -143,17 +187,16 @@ describe API::Vulnerabilities do ...@@ -143,17 +187,16 @@ describe API::Vulnerabilities do
it_behaves_like 'forbids actions on vulnerability in case of disabled features' it_behaves_like 'forbids actions on vulnerability in case of disabled features'
end end
it_behaves_like 'prevents working with vulnerabilities in case of insufficient privileges' it_behaves_like 'prevents working with vulnerabilities in case of insufficient access level'
it_behaves_like 'prevents working with vulnerabilities for anonymous users'
end end
describe "POST /vulnerabilities:id/resolve" do describe 'POST /vulnerabilities/:id/resolve' do
before do before do
create_list(:vulnerabilities_finding, 2, vulnerability: vulnerability) create_list(:vulnerabilities_finding, 2, vulnerability: vulnerability)
end end
let(:vulnerability) { project.vulnerabilities.first } subject(:resolve_vulnerability) { post api("/vulnerabilities/#{vulnerability_id}/resolve", user) }
subject { post api("/vulnerabilities/#{vulnerability.id}/resolve", user) }
context 'with an authorized user with proper permissions' do context 'with an authorized user with proper permissions' do
before do before do
...@@ -162,7 +205,7 @@ describe API::Vulnerabilities do ...@@ -162,7 +205,7 @@ describe API::Vulnerabilities do
it 'resolves a vulnerability and its associated findings' do it 'resolves a vulnerability and its associated findings' do
Timecop.freeze do Timecop.freeze do
subject resolve_vulnerability
expect(response).to have_gitlab_http_status(201) expect(response).to have_gitlab_http_status(201)
expect(response).to match_response_schema('vulnerability', dir: 'ee') expect(response).to match_response_schema('vulnerability', dir: 'ee')
...@@ -173,11 +216,13 @@ describe API::Vulnerabilities do ...@@ -173,11 +216,13 @@ describe API::Vulnerabilities do
end end
end end
it_behaves_like 'responds with "not found" for an unknown vulnerability ID'
context 'when the vulnerability is already resolved' do context 'when the vulnerability is already resolved' do
let(:vulnerability) { create(:vulnerability, :closed, project: project) } let(:vulnerability) { create(:vulnerability, :closed, project: project) }
it 'responds with 304 Not Modified response' do it 'responds with 304 Not Modified response' do
subject resolve_vulnerability
expect(response).to have_gitlab_http_status(304) expect(response).to have_gitlab_http_status(304)
end end
...@@ -186,6 +231,7 @@ describe API::Vulnerabilities do ...@@ -186,6 +231,7 @@ describe API::Vulnerabilities do
it_behaves_like 'forbids actions on vulnerability in case of disabled features' it_behaves_like 'forbids actions on vulnerability in case of disabled features'
end end
it_behaves_like 'prevents working with vulnerabilities in case of insufficient privileges' it_behaves_like 'prevents working with vulnerabilities in case of insufficient access level'
it_behaves_like 'prevents working with vulnerabilities for anonymous users'
end end
end end
...@@ -181,7 +181,7 @@ describe API::VulnerabilityFindings do ...@@ -181,7 +181,7 @@ describe API::VulnerabilityFindings do
subject { get api(project_vulnerability_findings_path, user) } subject { get api(project_vulnerability_findings_path, user) }
end end
it_behaves_like 'prevents working with vulnerabilities in case of insufficient privileges' do it_behaves_like 'prevents working with vulnerabilities in case of insufficient access level' do
subject { get api(project_vulnerability_findings_path, user) } subject { get api(project_vulnerability_findings_path, user) }
end end
end end
......
# frozen_string_literal: true # frozen_string_literal: true
shared_examples 'prevents working with vulnerabilities in case of insufficient privileges' do shared_examples 'prevents working with vulnerabilities in case of insufficient access level' do
context 'with lesser access level than required' do it 'responds 403 Forbidden when accessed by reporter' do
it 'responds with 403 Forbidden' do project.add_reporter(user)
project.add_reporter(user)
subject subject
expect(response).to have_gitlab_http_status(403) expect(response).to have_gitlab_http_status(403)
end end
it 'responds 403 Forbidden when accessed by guest' do
project.add_guest(user)
subject
expect(response).to have_gitlab_http_status(403)
end 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