Commit 4b6941e0 authored by Dmitriy Zaporozhets's avatar Dmitriy Zaporozhets

Merge branch '34422-get-single-vulnerability-api' into 'master'

Get single Vulnerability API call

See merge request gitlab-org/gitlab!19819
parents 4762e42e 4d67f718
...@@ -13,9 +13,13 @@ module API ...@@ -13,9 +13,13 @@ 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
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 +42,15 @@ module API ...@@ -38,6 +42,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 EE::API::Entities::Vulnerability
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 EE::API::Entities::Vulnerability success EE::API::Entities::Vulnerability
end end
......
...@@ -25,14 +25,9 @@ ...@@ -25,14 +25,9 @@
] ]
}, },
"project": { "project": {
"required": ["id", "name", "name_with_namespace", "description", "path", "path_with_namespace", "created_at"], "oneOf": [
"id": { "type": "integer" }, { "$ref": "../../../../../../../spec/fixtures/api/schemas/public_api/v4/project/identity.json" }
"name": { "type": "string" }, ]
"name_with_namespace": { "type": "string" },
"description": { "type": ["string", "null"] },
"path": { "type": "string" },
"path_with_namespace": { "type": "string" },
"created_at": { "type": "date" }
}, },
"author_id": { "type": "integer" }, "author_id": { "type": "integer" },
"updated_by_id": { "type": ["integer", "null"] }, "updated_by_id": { "type": ["integer", "null"] },
......
...@@ -38,6 +38,16 @@ describe API::Vulnerabilities do ...@@ -38,6 +38,16 @@ 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_it_be(:project) { create(:project, :with_vulnerabilities) } let_it_be(:project) { create(:project, :with_vulnerabilities) }
...@@ -84,6 +94,43 @@ describe API::Vulnerabilities do ...@@ -84,6 +94,43 @@ describe API::Vulnerabilities do
end end
end end
describe 'GET /vulnerabilities/:id' do
let_it_be(:project) { create(:project, :with_vulnerabilities) }
let_it_be(:vulnerability) { project.vulnerabilities.first }
let(:vulnerability_id) { vulnerability.id }
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('public_api/v4/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
describe 'permissions' do
it { expect { get_vulnerability }.to be_allowed_for(:admin) }
it { expect { get_vulnerability }.to be_allowed_for(:owner).of(project) }
it { expect { get_vulnerability }.to be_allowed_for(:maintainer).of(project) }
it { expect { get_vulnerability }.to be_allowed_for(:developer).of(project) }
it { expect { get_vulnerability }.to be_allowed_for(:auditor) }
it { expect { get_vulnerability }.to be_denied_for(:reporter).of(project) }
it { expect { get_vulnerability }.to be_denied_for(:guest).of(project) }
it { expect { get_vulnerability }.to be_denied_for(:anonymous) }
end
end
describe 'POST /projects/:id/vulnerabilities' do describe 'POST /projects/:id/vulnerabilities' do
let_it_be(:project) { create(:project) } let_it_be(:project) { create(:project) }
let(:finding) { create(:vulnerabilities_occurrence, project: project) } let(:finding) { create(:vulnerabilities_occurrence, project: project) }
...@@ -162,8 +209,9 @@ describe API::Vulnerabilities do ...@@ -162,8 +209,9 @@ describe API::Vulnerabilities do
let_it_be(:project) { create(:project, :with_vulnerabilities) } let_it_be(:project) { create(:project, :with_vulnerabilities) }
let(:vulnerability) { project.vulnerabilities.first } let(:vulnerability) { project.vulnerabilities.first }
let(:vulnerability_id) { vulnerability.id }
subject(:dismiss_vulnerability) { post api("/vulnerabilities/#{vulnerability.id}/dismiss", user) } subject(:dismiss_vulnerability) { 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
...@@ -183,6 +231,8 @@ describe API::Vulnerabilities do ...@@ -183,6 +231,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|
...@@ -239,15 +289,16 @@ describe API::Vulnerabilities do ...@@ -239,15 +289,16 @@ describe API::Vulnerabilities do
end end
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_it_be(:project) { create(:project, :with_vulnerabilities) } let_it_be(:project) { create(:project, :with_vulnerabilities) }
let(:vulnerability) { project.vulnerabilities.first } let(:vulnerability) { project.vulnerabilities.first }
let(:vulnerability_id) { vulnerability.id }
subject(:resolve_vulnerability) { post api("/vulnerabilities/#{vulnerability.id}/resolve", user) } subject(:resolve_vulnerability) { 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
...@@ -267,6 +318,8 @@ describe API::Vulnerabilities do ...@@ -267,6 +318,8 @@ 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, :resolved, project: project) } let(:vulnerability) { create(:vulnerability, :resolved, project: project) }
......
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