# frozen_string_literal: true module Gitlab module Ci module Pipeline module Chain class Build class Associations < Chain::Base include Gitlab::Allowable include Chain::Helpers def perform! assign_pipeline_variables assign_source_pipeline end def break? @pipeline.errors.any? end private def assign_pipeline_variables @pipeline.variables_attributes = variables_attributes end def assign_source_pipeline return unless @command.bridge @pipeline.build_source_pipeline( source_pipeline: @command.bridge.pipeline, source_project: @command.bridge.project, source_bridge: @command.bridge, project: @command.project ) end def variables_attributes variables = Array(@command.variables_attributes) variables = apply_permissions(variables) validate_uniqueness(variables) end def apply_permissions(variables) # We allow parent pipelines to pass variables to child pipelines since # these variables are coming from internal configurations. We will check # permissions to :set_pipeline_variables when those are injected upstream, # to the parent pipeline. # In other scenarios (e.g. multi-project pipelines or run pipeline via UI) # the variables are provided from the outside and those should be guarded. return variables if @command.creates_child_pipeline? if variables.present? && !can?(@command.current_user, :set_pipeline_variables, @command.project) error("Insufficient permissions to set pipeline variables") variables = [] end variables end def validate_uniqueness(variables) duplicated_keys = variables .map { |var| var[:key] } .tally .filter_map { |key, count| key if count > 1 } if duplicated_keys.empty? variables else error(duplicate_variables_message(duplicated_keys), config_error: true) [] end end def duplicate_variables_message(keys) "Duplicate variable #{'name'.pluralize(keys.size)}: #{keys.join(', ')}" end end end end end end end