diff --git a/doc/api/vulnerabilities.md b/doc/api/vulnerabilities.md index cc6e5d3960b0ae2835feb0997f84ade300165d98..eaa4c13de55783560a138f9e8a5e49bb39439d4d 100644 --- a/doc/api/vulnerabilities.md +++ b/doc/api/vulnerabilities.md @@ -30,6 +30,7 @@ GET /projects/:id/vulnerabilities?scope=all GET /projects/:id/vulnerabilities?scope=dismissed GET /projects/:id/vulnerabilities?severity=high GET /projects/:id/vulnerabilities?confidence=unknown,experimental +GET /projects/:id/vulnerabilities?pipeline_id=42 ``` | Attribute | Type | Required | Description | @@ -39,6 +40,7 @@ GET /projects/:id/vulnerabilities?confidence=unknown,experimental | `scope` | string | no | Returns vulnerabilities for the given scope: `all` or `dismissed`. Defaults to `dismissed` | | `severity` | string array | no | Returns vulnerabilities belonging to specified severity level: `undefined`, `info`, `unknown`, `low`, `medium`, `high`, or `critical`. Defaults to all' | | `confidence` | string array | no | Returns vulnerabilities belonging to specified confidence level: `undefined`, `ignore`, `unknown`, `experimental`, `low`, `medium`, `high`, or `confirmed`. Defaults to all | +| `pipeline_id` | integer/string | no | Returns vulnerabilities belonging to specified pipeline. | ```bash curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/4/vulnerabilities diff --git a/ee/changelogs/unreleased/rf-optional-pipeline-for-vulnerabilities-api.yml b/ee/changelogs/unreleased/rf-optional-pipeline-for-vulnerabilities-api.yml new file mode 100644 index 0000000000000000000000000000000000000000..8eb6d9e47392d1bc34e768fbb139b88e5c2060f5 --- /dev/null +++ b/ee/changelogs/unreleased/rf-optional-pipeline-for-vulnerabilities-api.yml @@ -0,0 +1,5 @@ +--- +title: 'Add Vulnerabilities API scoping: pipeline' +merge_request: 14376 +author: +type: added diff --git a/ee/lib/api/vulnerabilities.rb b/ee/lib/api/vulnerabilities.rb index 1017f83fd28c050731487489919c0e6ca3d4501d..3595a491ee466c54afc77a2a28f7fb5a218e8391 100644 --- a/ee/lib/api/vulnerabilities.rb +++ b/ee/lib/api/vulnerabilities.rb @@ -6,7 +6,11 @@ module API helpers do def vulnerability_occurrences_by(params) - pipeline = params[:project].latest_pipeline_with_security_reports + pipeline = if params[:pipeline_id] + params[:project].ci_pipelines.find_by(id: params[:pipeline_id]) # rubocop:disable CodeReuse/ActiveRecord + else + params[:project].latest_pipeline_with_security_reports + end return [] unless pipeline @@ -38,6 +42,7 @@ module API type: Array[String], desc: 'Returns vulnerabilities belonging to specified confidence level: `undefined`, `ignore`, `unknown`, `experimental`, `low`, `medium`, `high`, or `confirmed`. Defaults to all', default: ::Vulnerabilities::Occurrence.confidences.keys + optional :pipeline_id, type: String, desc: 'The ID of the pipeline' use :pagination end diff --git a/ee/spec/requests/api/vulnerabilities_spec.rb b/ee/spec/requests/api/vulnerabilities_spec.rb index 8ddef4ae1ced0b9fe1cd7556c2066af55aca7201..6238ba33770e9c1d9cdc0b9eb6a0cdab6c8ed4d4 100644 --- a/ee/spec/requests/api/vulnerabilities_spec.rb +++ b/ee/spec/requests/api/vulnerabilities_spec.rb @@ -7,6 +7,7 @@ describe API::Vulnerabilities do set(:user) { create(:user) } let(:pipeline) { create(:ci_empty_pipeline, status: :created, project: project) } + let(:pipeline_without_vulnerabilities) { create(:ci_pipeline_without_jobs, status: :created, project: project) } let(:build_ds) { create(:ci_build, :success, name: 'ds_job', pipeline: pipeline, project: project) } let(:build_sast) { create(:ci_build, :success, name: 'sast_job', pipeline: pipeline, project: project) } @@ -105,6 +106,34 @@ describe API::Vulnerabilities do expect(json_response.map { |v| v['confidence'] }.uniq).to eq %w[high] end + + context 'when pipeline_id is supplied' do + it 'returns vulnerabilities from supplied pipeline' do + occurrence_count = (sast_report.occurrences.count + ds_report.occurrences.count - 1).to_s + + get api("/projects/#{project.id}/vulnerabilities", user), params: { per_page: 40, pipeline_id: pipeline.id } + + expect(response).to have_gitlab_http_status(200) + + expect(response.headers['X-Total']).to eq occurrence_count + end + + context 'pipeline has no reports' do + it 'returns empty results' do + get api("/projects/#{project.id}/vulnerabilities", user), params: { per_page: 40, pipeline_id: pipeline_without_vulnerabilities.id } + + expect(json_response).to eq [] + end + end + + context 'with unknown pipeline' do + it 'returns empty results' do + get api("/projects/#{project.id}/vulnerabilities", user), params: { per_page: 40, pipeline_id: 0 } + + expect(json_response).to eq [] + end + end + end end end