Commit 792a71db authored by Alan (Maciej) Paruszewski's avatar Alan (Maciej) Paruszewski Committed by Alper Akgun

Add API to revert vulnerability to reverted state

This change adds new API (vulnerabilities/:id/revert) to revert
vulnerability back to reverted state.
parent 960df1a4
...@@ -220,3 +220,53 @@ Example response: ...@@ -220,3 +220,53 @@ Example response:
"closed_at": null "closed_at": null
} }
``` ```
## Revert vulnerability to detected state
Reverts a given vulnerability to detected state. Returns status code `304` if the vulnerability is already in detected state.
If an authenticated user does not have permission to
[revert vulnerability to detected state](../user/permissions.md#project-members-permissions),
this request will result in a `403` status code.
```plaintext
POST /vulnerabilities/:id/revert
```
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | integer or string | yes | The ID of a vulnerability to revert to detected state |
```shell
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/vulnerabilities/5/dismiss"
```
Example response:
```json
{
"id": 2,
"title": "Predictable pseudorandom number generator",
"description": null,
"state": "detected",
"severity": "medium",
"confidence": "medium",
"report_type": "sast",
"project": {
"id": 32,
"name": "security-reports",
"full_path": "/gitlab-examples/security/security-reports",
"full_name": "gitlab-examples / security / security-reports"
},
"author_id": 1,
"updated_by_id": null,
"last_edited_by_id": null,
"closed_by_id": null,
"start_date": null,
"due_date": null,
"created_at": "2019-10-13T15:08:40.219Z",
"updated_at": "2019-10-13T15:09:40.382Z",
"last_edited_at": null,
"closed_at": null
}
```
...@@ -116,6 +116,7 @@ The following table depicts the various user permission levels in a project. ...@@ -116,6 +116,7 @@ The following table depicts the various user permission levels in a project.
| Create vulnerability from vulnerability finding **(ULTIMATE)** | | | ✓ | ✓ | ✓ | | Create vulnerability from vulnerability finding **(ULTIMATE)** | | | ✓ | ✓ | ✓ |
| Resolve vulnerability **(ULTIMATE)** | | | ✓ | ✓ | ✓ | | Resolve vulnerability **(ULTIMATE)** | | | ✓ | ✓ | ✓ |
| Dismiss vulnerability **(ULTIMATE)** | | | ✓ | ✓ | ✓ | | Dismiss vulnerability **(ULTIMATE)** | | | ✓ | ✓ | ✓ |
| Revert vulnerability to detected state **(ULTIMATE)** | | | ✓ | ✓ | ✓ |
| Apply code change suggestions | | | ✓ | ✓ | ✓ | | Apply code change suggestions | | | ✓ | ✓ | ✓ |
| Create and edit wiki pages | | | ✓ | ✓ | ✓ | | Create and edit wiki pages | | | ✓ | ✓ | ✓ |
| Rewrite/remove Git tags | | | ✓ | ✓ | ✓ | | Rewrite/remove Git tags | | | ✓ | ✓ | ✓ |
......
---
title: Add API to revert vulnerability to reverted state
merge_request: 41784
author:
type: added
...@@ -69,6 +69,16 @@ module API ...@@ -69,6 +69,16 @@ module API
@vulnerability = ::Vulnerabilities::ConfirmService.new(current_user, @vulnerability).execute @vulnerability = ::Vulnerabilities::ConfirmService.new(current_user, @vulnerability).execute
render_vulnerability(@vulnerability) render_vulnerability(@vulnerability)
end end
desc 'Revert a vulnerability to a detected state' do
success EE::API::Entities::Vulnerability
end
post ':id/revert' do
not_modified! if @vulnerability.detected?
@vulnerability = ::Vulnerabilities::RevertToDetectedService.new(current_user, @vulnerability).execute
render_vulnerability(@vulnerability)
end
end end
params do params do
......
...@@ -375,4 +375,92 @@ RSpec.describe API::Vulnerabilities do ...@@ -375,4 +375,92 @@ RSpec.describe API::Vulnerabilities do
it { expect { confirm_vulnerability }.to be_denied_for(:anonymous) } it { expect { confirm_vulnerability }.to be_denied_for(:anonymous) }
end end
end end
describe 'POST /vulnerabilities:id/revert' do
before do
create_list(:vulnerabilities_occurrence, 2, vulnerability: vulnerability, project: vulnerability.project)
end
let_it_be(:project) { create(:project) }
let_it_be(:vulnerability) { create(:vulnerability, :dismissed, project: project) }
let(:vulnerability_id) { vulnerability.id }
subject(:revert_vulnerability_to_detected) { post api("/vulnerabilities/#{vulnerability_id}/revert", user) }
context 'with an authorized user with proper permissions' do
before do
project.add_developer(user)
end
it 'reverts a vulnerability and its associated findings to detected state' do
Timecop.freeze do
revert_vulnerability_to_detected
expect(response).to have_gitlab_http_status(:created)
expect(response).to match_response_schema('public_api/v4/vulnerability', dir: 'ee')
expect(vulnerability.reload).to(
have_attributes(state: 'detected', dismissed_by: nil, dismissed_at: nil))
expect(vulnerability.findings).to all not_have_vulnerability_dismissal_feedback
end
end
it_behaves_like 'responds with "not found" for an unknown vulnerability ID'
context 'when there is a revert error' do
before do
Grape::Endpoint.before_each do |endpoint|
allow(endpoint).to receive(:find_vulnerability!).and_wrap_original do |method, *args|
vulnerability = method.call(*args)
errors = ActiveModel::Errors.new(vulnerability)
errors.add(:base, 'something went wrong')
allow(vulnerability).to receive(:valid?).and_return(false)
allow(vulnerability).to receive(:errors).and_return(errors)
vulnerability
end
end
end
after do
# resetting according to the https://github.com/ruby-grape/grape#stubbing-helpers
Grape::Endpoint.before_each nil
end
it 'responds with error' do
revert_vulnerability_to_detected
expect(response).to have_gitlab_http_status(:bad_request)
expect(json_response['message']).to eq('base' => ['something went wrong'])
end
end
context 'if a vulnerability is already in detected state' do
let(:vulnerability) { create(:vulnerability, :detected, project: project) }
it 'responds with 304 Not Modified' do
revert_vulnerability_to_detected
expect(response).to have_gitlab_http_status(:not_modified)
end
end
it_behaves_like 'forbids access to vulnerability API endpoint in case of disabled features'
end
describe 'permissions' do
it { expect { revert_vulnerability_to_detected }.to be_allowed_for(:admin) }
it { expect { revert_vulnerability_to_detected }.to be_allowed_for(:owner).of(project) }
it { expect { revert_vulnerability_to_detected }.to be_allowed_for(:maintainer).of(project) }
it { expect { revert_vulnerability_to_detected }.to be_allowed_for(:developer).of(project) }
it { expect { revert_vulnerability_to_detected }.to be_denied_for(:auditor) }
it { expect { revert_vulnerability_to_detected }.to be_denied_for(:reporter).of(project) }
it { expect { revert_vulnerability_to_detected }.to be_denied_for(:guest).of(project) }
it { expect { revert_vulnerability_to_detected }.to be_denied_for(:anonymous) }
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