Commit 7402bea1 authored by GitLab Release Tools Bot's avatar GitLab Release Tools Bot

Merge branch 'security-commits-api-last-pipeline-status' into 'master'

Show last_pipeline in commits API only if user can read pipeline

Closes #5

See merge request gitlab-org/security/gitlab!13
parents 91091445 0084286d
---
title: Disable access to last_pipeline in commits API for users without read permissions
merge_request:
author:
type: security
......@@ -154,7 +154,7 @@ module API
not_found! 'Commit' unless commit
present commit, with: Entities::CommitDetail, stats: params[:stats]
present commit, with: Entities::CommitDetail, stats: params[:stats], current_user: current_user
end
desc 'Get the diff for a specific commit of a project' do
......
......@@ -328,8 +328,18 @@ module API
class CommitDetail < Commit
expose :stats, using: Entities::CommitStats, if: :stats
expose :status
expose :last_pipeline, using: 'API::Entities::PipelineBasic'
expose :project_id
expose :last_pipeline do |commit, options|
pipeline = commit.last_pipeline if can_read_pipeline?
::API::Entities::PipelineBasic.represent(pipeline, options)
end
private
def can_read_pipeline?
Ability.allowed?(options[:current_user], :read_pipeline, object.last_pipeline)
end
end
class CommitSignature < Grape::Entity
......
......@@ -8,6 +8,7 @@ describe API::Commits do
let(:user) { create(:user) }
let(:guest) { create(:user).tap { |u| project.add_guest(u) } }
let(:developer) { create(:user).tap { |u| project.add_developer(u) } }
let(:project) { create(:project, :repository, creator: user, path: 'my.project') }
let(:branch_with_dot) { project.repository.find_branch('ends-with.json') }
let(:branch_with_slash) { project.repository.find_branch('improve/awesome') }
......@@ -964,6 +965,56 @@ describe API::Commits do
end
end
shared_examples_for 'ref with pipeline' do
let!(:pipeline) do
project
.ci_pipelines
.create!(source: :push, ref: 'master', sha: commit.sha, protected: false)
end
it 'includes status as "created" and a last_pipeline object' do
get api(route, current_user)
expect(response).to have_gitlab_http_status(200)
expect(response).to match_response_schema('public_api/v4/commit/detail')
expect(json_response['status']).to eq('created')
expect(json_response['last_pipeline']['id']).to eq(pipeline.id)
expect(json_response['last_pipeline']['ref']).to eq(pipeline.ref)
expect(json_response['last_pipeline']['sha']).to eq(pipeline.sha)
expect(json_response['last_pipeline']['status']).to eq(pipeline.status)
end
context 'when pipeline succeeds' do
before do
pipeline.update!(status: 'success')
end
it 'includes a "success" status' do
get api(route, current_user)
expect(response).to have_gitlab_http_status(200)
expect(response).to match_response_schema('public_api/v4/commit/detail')
expect(json_response['status']).to eq('success')
end
end
end
shared_examples_for 'ref with unaccessible pipeline' do
let!(:pipeline) do
project
.ci_pipelines
.create!(source: :push, ref: 'master', sha: commit.sha, protected: false)
end
it 'does not include last_pipeline' do
get api(route, current_user)
expect(response).to match_response_schema('public_api/v4/commit/detail')
expect(response).to have_gitlab_http_status(200)
expect(json_response['last_pipeline']).to be_nil
end
end
context 'when stat param' do
let(:route) { "/projects/#{project_id}/repository/commits/#{commit_id}" }
......@@ -993,6 +1044,15 @@ describe API::Commits do
let(:project) { create(:project, :public, :repository) }
it_behaves_like 'ref commit'
it_behaves_like 'ref with pipeline'
context 'with private builds' do
before do
project.project_feature.update!(builds_access_level: ProjectFeature::PRIVATE)
end
it_behaves_like 'ref with unaccessible pipeline'
end
end
context 'when unauthenticated', 'and project is private' do
......@@ -1006,6 +1066,17 @@ describe API::Commits do
let(:current_user) { user }
it_behaves_like 'ref commit'
it_behaves_like 'ref with pipeline'
context 'when builds are disabled' do
before do
project
.project_feature
.update!(builds_access_level: ProjectFeature::DISABLED)
end
it_behaves_like 'ref with unaccessible pipeline'
end
context 'when branch contains a dot' do
let(:commit) { project.repository.commit(branch_with_dot.name) }
......@@ -1041,35 +1112,53 @@ describe API::Commits do
it_behaves_like 'ref commit'
end
end
end
context 'when the ref has a pipeline' do
let!(:pipeline) { project.ci_pipelines.create(source: :push, ref: 'master', sha: commit.sha, protected: false) }
context 'when authenticated', 'as a developer' do
let(:current_user) { developer }
it 'includes a "created" status' do
get api(route, current_user)
it_behaves_like 'ref commit'
it_behaves_like 'ref with pipeline'
expect(response).to have_gitlab_http_status(200)
expect(response).to match_response_schema('public_api/v4/commit/detail')
expect(json_response['status']).to eq('created')
expect(json_response['last_pipeline']['id']).to eq(pipeline.id)
expect(json_response['last_pipeline']['ref']).to eq(pipeline.ref)
expect(json_response['last_pipeline']['sha']).to eq(pipeline.sha)
expect(json_response['last_pipeline']['status']).to eq(pipeline.status)
context 'with private builds' do
before do
project.project_feature.update!(builds_access_level: ProjectFeature::PRIVATE)
end
context 'when pipeline succeeds' do
before do
pipeline.update(status: 'success')
end
it_behaves_like 'ref with pipeline'
end
end
it 'includes a "success" status' do
get api(route, current_user)
context 'when authenticated', 'as a guest' do
let(:current_user) { guest }
expect(response).to have_gitlab_http_status(200)
expect(response).to match_response_schema('public_api/v4/commit/detail')
expect(json_response['status']).to eq('success')
end
it_behaves_like '403 response' do
let(:request) { get api(route, guest) }
let(:message) { '403 Forbidden' }
end
end
context 'when authenticated', 'as a non member' do
let(:current_user) { create(:user) }
it_behaves_like '403 response' do
let(:request) { get api(route, guest) }
let(:message) { '403 Forbidden' }
end
end
context 'when authenticated', 'as non_member and project is public' do
let(:current_user) { create(:user) }
let(:project) { create(:project, :public, :repository) }
it_behaves_like 'ref with pipeline'
context 'with private builds' do
before do
project.project_feature.update!(builds_access_level: ProjectFeature::PRIVATE)
end
it_behaves_like 'ref with unaccessible pipeline'
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