diff options
Diffstat (limited to 'app/services/ci/create_pipeline_service.rb')
-rw-r--r-- | app/services/ci/create_pipeline_service.rb | 81 |
1 files changed, 64 insertions, 17 deletions
diff --git a/app/services/ci/create_pipeline_service.rb b/app/services/ci/create_pipeline_service.rb index 273386776fa..884b681ff81 100644 --- a/app/services/ci/create_pipeline_service.rb +++ b/app/services/ci/create_pipeline_service.rb @@ -15,12 +15,48 @@ module Ci pipeline_schedule: schedule ) + result = validate(current_user || trigger_request.trigger.owner, + ignore_skip_ci: ignore_skip_ci, + save_on_errors: save_on_errors) + + return result if result + + begin + Ci::Pipeline.transaction do + pipeline.save! + + yield(pipeline) if block_given? + + Ci::CreatePipelineStagesService + .new(project, current_user) + .execute(pipeline) + end + rescue ActiveRecord::RecordInvalid => e + return error("Failed to persist the pipeline: #{e}") + end + + update_merge_requests_head_pipeline + + cancel_pending_pipelines if project.auto_cancel_pending_pipelines? + + pipeline_created_counter.increment(source: source) + + pipeline.tap(&:process!) + end + + private + + def validate(triggering_user, ignore_skip_ci:, save_on_errors:) unless project.builds_enabled? return error('Pipeline is disabled') end - unless trigger_request || can?(current_user, :create_pipeline, project) - return error('Insufficient permissions to create a new pipeline') + unless allowed_to_trigger_pipeline?(triggering_user) + if can?(triggering_user, :create_pipeline, project) + return error("Insufficient permissions for protected ref '#{ref}'") + else + return error('Insufficient permissions to create a new pipeline') + end end unless branch? || tag? @@ -46,24 +82,29 @@ module Ci unless pipeline.has_stage_seeds? return error('No stages / jobs for this pipeline.') end + end - Ci::Pipeline.transaction do - update_merge_requests_head_pipeline if pipeline.save - - Ci::CreatePipelineStagesService - .new(project, current_user) - .execute(pipeline) + def allowed_to_trigger_pipeline?(triggering_user) + if triggering_user + allowed_to_create?(triggering_user) + else # legacy triggers don't have a corresponding user + !project.protected_for?(ref) end + end - cancel_pending_pipelines if project.auto_cancel_pending_pipelines? + def allowed_to_create?(triggering_user) + access = Gitlab::UserAccess.new(triggering_user, project: project) - pipeline_created_counter.increment(source: source) - - pipeline.tap(&:process!) + can?(triggering_user, :create_pipeline, project) && + if branch? + access.can_update_branch?(ref) + elsif tag? + access.can_create_tag?(ref) + else + true # Allow it for now and we'll reject when we check ref existence + end end - private - def update_merge_requests_head_pipeline return unless pipeline.latest? @@ -113,15 +154,21 @@ module Ci end def branch? - project.repository.ref_exists?(Gitlab::Git::BRANCH_REF_PREFIX + ref) + return @is_branch if defined?(@is_branch) + + @is_branch = + project.repository.ref_exists?(Gitlab::Git::BRANCH_REF_PREFIX + ref) end def tag? - project.repository.ref_exists?(Gitlab::Git::TAG_REF_PREFIX + ref) + return @is_tag if defined?(@is_tag) + + @is_tag = + project.repository.ref_exists?(Gitlab::Git::TAG_REF_PREFIX + ref) end def ref - Gitlab::Git.ref_name(origin_ref) + @ref ||= Gitlab::Git.ref_name(origin_ref) end def valid_sha? |