debian-mirror-gitlab/lib/gitlab/ci/pipeline/chain/validate/external.rb

144 lines
4.7 KiB
Ruby
Raw Normal View History

2020-01-01 13:55:28 +05:30
# frozen_string_literal: true
module Gitlab
module Ci
module Pipeline
module Chain
module Validate
class External < Chain::Base
include Chain::Helpers
InvalidResponseCode = Class.new(StandardError)
2021-04-29 21:17:54 +05:30
DEFAULT_VALIDATION_REQUEST_TIMEOUT = 5
ACCEPTED_STATUS = 200
2021-09-04 01:27:46 +05:30
REJECTED_STATUS = 406
2020-01-01 13:55:28 +05:30
def perform!
2020-04-22 19:07:51 +05:30
pipeline_authorized = validate_external
log_message = pipeline_authorized ? 'authorized' : 'not authorized'
2021-04-29 21:17:54 +05:30
Gitlab::AppLogger.info(message: "Pipeline #{log_message}", project_id: project.id, user_id: current_user.id)
2020-04-22 19:07:51 +05:30
error('External validation failed', drop_reason: :external_validation_failure) unless pipeline_authorized
2020-01-01 13:55:28 +05:30
end
def break?
2021-04-29 21:17:54 +05:30
pipeline.errors.any?
2020-01-01 13:55:28 +05:30
end
private
def validate_external
return true unless validation_service_url
# 200 - accepted
2021-09-04 01:27:46 +05:30
# 406 - rejected
2020-01-01 13:55:28 +05:30
# everything else - accepted and logged
response_code = validate_service_request.code
case response_code
2021-04-29 21:17:54 +05:30
when ACCEPTED_STATUS
2020-01-01 13:55:28 +05:30
true
2021-09-04 01:27:46 +05:30
when REJECTED_STATUS
2020-01-01 13:55:28 +05:30
false
else
raise InvalidResponseCode, "Unsupported response code received from Validation Service: #{response_code}"
end
2021-06-08 01:23:25 +05:30
rescue StandardError => ex
2021-04-29 21:17:54 +05:30
Gitlab::ErrorTracking.track_exception(ex, project_id: project.id)
2020-01-01 13:55:28 +05:30
true
end
def validate_service_request
2021-04-29 21:17:54 +05:30
headers = {
'X-Gitlab-Correlation-id' => Labkit::Correlation::CorrelationId.current_id,
'X-Gitlab-Token' => validation_service_token
}.compact
2020-01-01 13:55:28 +05:30
Gitlab::HTTP.post(
2021-04-29 21:17:54 +05:30
validation_service_url, timeout: validation_service_timeout,
headers: headers,
body: validation_service_payload.to_json
2020-01-01 13:55:28 +05:30
)
end
2021-04-29 21:17:54 +05:30
def validation_service_timeout
timeout = Gitlab::CurrentSettings.external_pipeline_validation_service_timeout || ENV['EXTERNAL_VALIDATION_SERVICE_TIMEOUT'].to_i
return timeout if timeout > 0
DEFAULT_VALIDATION_REQUEST_TIMEOUT
end
2020-01-01 13:55:28 +05:30
def validation_service_url
2021-04-29 21:17:54 +05:30
Gitlab::CurrentSettings.external_pipeline_validation_service_url || ENV['EXTERNAL_VALIDATION_SERVICE_URL']
end
def validation_service_token
Gitlab::CurrentSettings.external_pipeline_validation_service_token || ENV['EXTERNAL_VALIDATION_SERVICE_TOKEN']
2020-01-01 13:55:28 +05:30
end
2021-04-29 21:17:54 +05:30
def validation_service_payload
2020-01-01 13:55:28 +05:30
{
project: {
2021-04-29 21:17:54 +05:30
id: project.id,
path: project.full_path,
created_at: project.created_at&.iso8601
2020-01-01 13:55:28 +05:30
},
user: {
2021-04-29 21:17:54 +05:30
id: current_user.id,
username: current_user.username,
email: current_user.email,
2021-09-04 01:27:46 +05:30
created_at: current_user.created_at&.iso8601,
current_sign_in_ip: current_user.current_sign_in_ip,
2021-11-18 22:05:49 +05:30
last_sign_in_ip: current_user.last_sign_in_ip,
sign_in_count: current_user.sign_in_count
2020-01-01 13:55:28 +05:30
},
pipeline: {
sha: pipeline.sha,
ref: pipeline.ref,
type: pipeline.source
},
2021-04-29 21:17:54 +05:30
builds: builds_validation_payload
}
2020-01-01 13:55:28 +05:30
end
2021-04-29 21:17:54 +05:30
def builds_validation_payload
stages_attributes.flat_map { |stage| stage[:builds] }
2020-01-01 13:55:28 +05:30
.map(&method(:build_validation_payload))
end
def build_validation_payload(build)
{
name: build[:name],
stage: build[:stage],
image: build.dig(:options, :image, :name),
2022-01-26 12:08:38 +05:30
services: service_names(build),
2020-01-01 13:55:28 +05:30
script: [
build.dig(:options, :before_script),
build.dig(:options, :script),
build.dig(:options, :after_script)
].flatten.compact
}
end
2021-04-29 21:17:54 +05:30
2022-01-26 12:08:38 +05:30
def service_names(build)
services = build.dig(:options, :services)
return unless services
services.compact.map { |service| service[:name] }
end
2021-04-29 21:17:54 +05:30
def stages_attributes
command.yaml_processor_result.stages_attributes
end
2020-01-01 13:55:28 +05:30
end
end
end
end
end
end
2021-04-29 21:17:54 +05:30
2021-06-08 01:23:25 +05:30
Gitlab::Ci::Pipeline::Chain::Validate::External.prepend_mod_with('Gitlab::Ci::Pipeline::Chain::Validate::External')