Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-09-19 04:45:44 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2020-09-19 04:45:44 +0300
commit85dc423f7090da0a52c73eb66faf22ddb20efff9 (patch)
tree9160f299afd8c80c038f08e1545be119f5e3f1e1 /lib/gitlab/ci
parent15c2c8c66dbe422588e5411eee7e68f1fa440bb8 (diff)
Add latest changes from gitlab-org/gitlab@13-4-stable-ee
Diffstat (limited to 'lib/gitlab/ci')
-rw-r--r--lib/gitlab/ci/ansi2html.rb200
-rw-r--r--lib/gitlab/ci/artifact_file_reader.rb25
-rw-r--r--lib/gitlab/ci/build/prerequisite/kubernetes_namespace.rb6
-rw-r--r--lib/gitlab/ci/config.rb4
-rw-r--r--lib/gitlab/ci/config/entry/job.rb34
-rw-r--r--lib/gitlab/ci/config/entry/jobs.rb10
-rw-r--r--lib/gitlab/ci/config/entry/root.rb2
-rw-r--r--lib/gitlab/ci/config/normalizer.rb1
-rw-r--r--lib/gitlab/ci/config/normalizer/matrix_strategy.rb13
-rw-r--r--lib/gitlab/ci/features.rb51
-rw-r--r--lib/gitlab/ci/lint.rb108
-rw-r--r--lib/gitlab/ci/mask_secret.rb5
-rw-r--r--lib/gitlab/ci/pipeline/chain/build.rb6
-rw-r--r--lib/gitlab/ci/pipeline/chain/command.rb2
-rw-r--r--lib/gitlab/ci/pipeline/chain/config/content/remote.rb2
-rw-r--r--lib/gitlab/ci/pipeline/chain/config/process.rb15
-rw-r--r--lib/gitlab/ci/pipeline/chain/evaluate_workflow_rules.rb2
-rw-r--r--lib/gitlab/ci/pipeline/chain/remove_unwanted_chat_jobs.rb4
-rw-r--r--lib/gitlab/ci/pipeline/chain/seed.rb4
-rw-r--r--lib/gitlab/ci/pipeline/chain/validate/external.rb2
-rw-r--r--lib/gitlab/ci/pipeline/expression/lexer.rb20
-rw-r--r--lib/gitlab/ci/pipeline/expression/parser.rb28
-rw-r--r--lib/gitlab/ci/pipeline/seed/build.rb8
-rw-r--r--lib/gitlab/ci/pipeline_object_hierarchy.rb45
-rw-r--r--lib/gitlab/ci/reports/test_case.rb2
-rw-r--r--lib/gitlab/ci/reports/test_suite.rb16
-rw-r--r--lib/gitlab/ci/status/bridge/common.rb18
-rw-r--r--lib/gitlab/ci/status/build/failed.rb3
-rw-r--r--lib/gitlab/ci/status/composite.rb11
-rw-r--r--lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml30
-rw-r--r--lib/gitlab/ci/templates/Jobs/Browser-Performance-Testing.gitlab-ci.yml8
-rw-r--r--lib/gitlab/ci/templates/Jobs/Code-Quality.gitlab-ci.yml26
-rw-r--r--lib/gitlab/ci/templates/Jobs/Deploy.gitlab-ci.yml3
-rw-r--r--lib/gitlab/ci/templates/Jobs/Deploy.latest.gitlab-ci.yml249
-rw-r--r--lib/gitlab/ci/templates/Jobs/Load-Performance-Testing.gitlab-ci.yml3
-rw-r--r--lib/gitlab/ci/templates/Managed-Cluster-Applications.gitlab-ci.yml18
-rw-r--r--lib/gitlab/ci/templates/Security/API-Fuzzing.gitlab-ci.yml10
-rw-r--r--lib/gitlab/ci/templates/Security/Coverage-Fuzzing.gitlab-ci.yml2
-rw-r--r--lib/gitlab/ci/templates/Security/Dependency-Scanning.gitlab-ci.yml98
-rw-r--r--lib/gitlab/ci/templates/Security/SAST.gitlab-ci.yml113
-rw-r--r--lib/gitlab/ci/templates/Security/Secret-Detection.gitlab-ci.yml5
-rw-r--r--lib/gitlab/ci/templates/Verify/Browser-Performance.gitlab-ci.yml6
-rw-r--r--lib/gitlab/ci/templates/Verify/Load-Performance-Testing.gitlab-ci.yml3
-rw-r--r--lib/gitlab/ci/templates/npm.gitlab-ci.yml2
-rw-r--r--lib/gitlab/ci/trace.rb39
-rw-r--r--lib/gitlab/ci/trace/metrics.rb44
-rw-r--r--lib/gitlab/ci/trace/stream.rb8
-rw-r--r--lib/gitlab/ci/warnings.rb5
-rw-r--r--lib/gitlab/ci/yaml_processor.rb192
-rw-r--r--lib/gitlab/ci/yaml_processor/result.rb120
50 files changed, 1070 insertions, 561 deletions
diff --git a/lib/gitlab/ci/ansi2html.rb b/lib/gitlab/ci/ansi2html.rb
index e145bd2e9df..1fac00337a3 100644
--- a/lib/gitlab/ci/ansi2html.rb
+++ b/lib/gitlab/ci/ansi2html.rb
@@ -31,105 +31,205 @@ module Gitlab
end
class Converter
- def on_0(_) reset end
+ def on_0(_)
+ reset
+ end
- def on_1(_) enable(STYLE_SWITCHES[:bold]) end
+ def on_1(_)
+ enable(STYLE_SWITCHES[:bold])
+ end
- def on_3(_) enable(STYLE_SWITCHES[:italic]) end
+ def on_3(_)
+ enable(STYLE_SWITCHES[:italic])
+ end
- def on_4(_) enable(STYLE_SWITCHES[:underline]) end
+ def on_4(_)
+ enable(STYLE_SWITCHES[:underline])
+ end
- def on_8(_) enable(STYLE_SWITCHES[:conceal]) end
+ def on_8(_)
+ enable(STYLE_SWITCHES[:conceal])
+ end
- def on_9(_) enable(STYLE_SWITCHES[:cross]) end
+ def on_9(_)
+ enable(STYLE_SWITCHES[:cross])
+ end
- def on_21(_) disable(STYLE_SWITCHES[:bold]) end
+ def on_21(_)
+ disable(STYLE_SWITCHES[:bold])
+ end
- def on_22(_) disable(STYLE_SWITCHES[:bold]) end
+ def on_22(_)
+ disable(STYLE_SWITCHES[:bold])
+ end
- def on_23(_) disable(STYLE_SWITCHES[:italic]) end
+ def on_23(_)
+ disable(STYLE_SWITCHES[:italic])
+ end
- def on_24(_) disable(STYLE_SWITCHES[:underline]) end
+ def on_24(_)
+ disable(STYLE_SWITCHES[:underline])
+ end
- def on_28(_) disable(STYLE_SWITCHES[:conceal]) end
+ def on_28(_)
+ disable(STYLE_SWITCHES[:conceal])
+ end
- def on_29(_) disable(STYLE_SWITCHES[:cross]) end
+ def on_29(_)
+ disable(STYLE_SWITCHES[:cross])
+ end
- def on_30(_) set_fg_color(0) end
+ def on_30(_)
+ set_fg_color(0)
+ end
- def on_31(_) set_fg_color(1) end
+ def on_31(_)
+ set_fg_color(1)
+ end
- def on_32(_) set_fg_color(2) end
+ def on_32(_)
+ set_fg_color(2)
+ end
- def on_33(_) set_fg_color(3) end
+ def on_33(_)
+ set_fg_color(3)
+ end
- def on_34(_) set_fg_color(4) end
+ def on_34(_)
+ set_fg_color(4)
+ end
- def on_35(_) set_fg_color(5) end
+ def on_35(_)
+ set_fg_color(5)
+ end
- def on_36(_) set_fg_color(6) end
+ def on_36(_)
+ set_fg_color(6)
+ end
- def on_37(_) set_fg_color(7) end
+ def on_37(_)
+ set_fg_color(7)
+ end
- def on_38(stack) set_fg_color_256(stack) end
+ def on_38(stack)
+ set_fg_color_256(stack)
+ end
- def on_39(_) set_fg_color(9) end
+ def on_39(_)
+ set_fg_color(9)
+ end
- def on_40(_) set_bg_color(0) end
+ def on_40(_)
+ set_bg_color(0)
+ end
- def on_41(_) set_bg_color(1) end
+ def on_41(_)
+ set_bg_color(1)
+ end
- def on_42(_) set_bg_color(2) end
+ def on_42(_)
+ set_bg_color(2)
+ end
- def on_43(_) set_bg_color(3) end
+ def on_43(_)
+ set_bg_color(3)
+ end
- def on_44(_) set_bg_color(4) end
+ def on_44(_)
+ set_bg_color(4)
+ end
- def on_45(_) set_bg_color(5) end
+ def on_45(_)
+ set_bg_color(5)
+ end
- def on_46(_) set_bg_color(6) end
+ def on_46(_)
+ set_bg_color(6)
+ end
- def on_47(_) set_bg_color(7) end
+ def on_47(_)
+ set_bg_color(7)
+ end
- def on_48(stack) set_bg_color_256(stack) end
+ def on_48(stack)
+ set_bg_color_256(stack)
+ end
- def on_49(_) set_bg_color(9) end
+ def on_49(_)
+ set_bg_color(9)
+ end
- def on_90(_) set_fg_color(0, 'l') end
+ def on_90(_)
+ set_fg_color(0, 'l')
+ end
- def on_91(_) set_fg_color(1, 'l') end
+ def on_91(_)
+ set_fg_color(1, 'l')
+ end
- def on_92(_) set_fg_color(2, 'l') end
+ def on_92(_)
+ set_fg_color(2, 'l')
+ end
- def on_93(_) set_fg_color(3, 'l') end
+ def on_93(_)
+ set_fg_color(3, 'l')
+ end
- def on_94(_) set_fg_color(4, 'l') end
+ def on_94(_)
+ set_fg_color(4, 'l')
+ end
- def on_95(_) set_fg_color(5, 'l') end
+ def on_95(_)
+ set_fg_color(5, 'l')
+ end
- def on_96(_) set_fg_color(6, 'l') end
+ def on_96(_)
+ set_fg_color(6, 'l')
+ end
- def on_97(_) set_fg_color(7, 'l') end
+ def on_97(_)
+ set_fg_color(7, 'l')
+ end
- def on_99(_) set_fg_color(9, 'l') end
+ def on_99(_)
+ set_fg_color(9, 'l')
+ end
- def on_100(_) set_bg_color(0, 'l') end
+ def on_100(_)
+ set_bg_color(0, 'l')
+ end
- def on_101(_) set_bg_color(1, 'l') end
+ def on_101(_)
+ set_bg_color(1, 'l')
+ end
- def on_102(_) set_bg_color(2, 'l') end
+ def on_102(_)
+ set_bg_color(2, 'l')
+ end
- def on_103(_) set_bg_color(3, 'l') end
+ def on_103(_)
+ set_bg_color(3, 'l')
+ end
- def on_104(_) set_bg_color(4, 'l') end
+ def on_104(_)
+ set_bg_color(4, 'l')
+ end
- def on_105(_) set_bg_color(5, 'l') end
+ def on_105(_)
+ set_bg_color(5, 'l')
+ end
- def on_106(_) set_bg_color(6, 'l') end
+ def on_106(_)
+ set_bg_color(6, 'l')
+ end
- def on_107(_) set_bg_color(7, 'l') end
+ def on_107(_)
+ set_bg_color(7, 'l')
+ end
- def on_109(_) set_bg_color(9, 'l') end
+ def on_109(_)
+ set_bg_color(9, 'l')
+ end
attr_accessor :offset, :n_open_tags, :fg_color, :bg_color, :style_mask, :sections, :lineno_in_section
diff --git a/lib/gitlab/ci/artifact_file_reader.rb b/lib/gitlab/ci/artifact_file_reader.rb
index c2d17cc176e..6395a20ca99 100644
--- a/lib/gitlab/ci/artifact_file_reader.rb
+++ b/lib/gitlab/ci/artifact_file_reader.rb
@@ -45,6 +45,31 @@ module Gitlab
end
def read_zip_file!(file_path)
+ if ::Gitlab::Ci::Features.new_artifact_file_reader_enabled?(job.project)
+ read_with_new_artifact_file_reader(file_path)
+ else
+ read_with_legacy_artifact_file_reader(file_path)
+ end
+ end
+
+ def read_with_new_artifact_file_reader(file_path)
+ job.artifacts_file.use_open_file do |file|
+ zip_file = Zip::File.new(file, false, true)
+ entry = zip_file.find_entry(file_path)
+
+ unless entry
+ raise Error, "Path `#{file_path}` does not exist inside the `#{job.name}` artifacts archive!"
+ end
+
+ if entry.name_is_directory?
+ raise Error, "Path `#{file_path}` was expected to be a file but it was a directory!"
+ end
+
+ zip_file.read(entry)
+ end
+ end
+
+ def read_with_legacy_artifact_file_reader(file_path)
job.artifacts_file.use_file do |archive_path|
Zip::File.open(archive_path) do |zip_file|
entry = zip_file.find_entry(file_path)
diff --git a/lib/gitlab/ci/build/prerequisite/kubernetes_namespace.rb b/lib/gitlab/ci/build/prerequisite/kubernetes_namespace.rb
index b64990d6a7a..72ef0a8d067 100644
--- a/lib/gitlab/ci/build/prerequisite/kubernetes_namespace.rb
+++ b/lib/gitlab/ci/build/prerequisite/kubernetes_namespace.rb
@@ -33,7 +33,7 @@ module Gitlab
def kubernetes_namespace
strong_memoize(:kubernetes_namespace) do
- Clusters::KubernetesNamespaceFinder.new(
+ ::Clusters::KubernetesNamespaceFinder.new(
deployment_cluster,
project: environment.project,
environment_name: environment.name,
@@ -47,7 +47,7 @@ module Gitlab
return if conflicting_ci_namespace_requested?(namespace)
- Clusters::Kubernetes::CreateOrUpdateNamespaceService.new(
+ ::Clusters::Kubernetes::CreateOrUpdateNamespaceService.new(
cluster: deployment_cluster,
kubernetes_namespace: namespace
).execute
@@ -71,7 +71,7 @@ module Gitlab
end
def build_namespace_record
- Clusters::BuildKubernetesNamespaceService.new(
+ ::Clusters::BuildKubernetesNamespaceService.new(
deployment_cluster,
environment: environment
).execute
diff --git a/lib/gitlab/ci/config.rb b/lib/gitlab/ci/config.rb
index d81a3fef1f5..9d269831679 100644
--- a/lib/gitlab/ci/config.rb
+++ b/lib/gitlab/ci/config.rb
@@ -62,6 +62,10 @@ module Gitlab
root.jobs_value
end
+ def normalized_jobs
+ @normalized_jobs ||= Ci::Config::Normalizer.new(jobs).normalize_jobs
+ end
+
private
def expand_config(config)
diff --git a/lib/gitlab/ci/config/entry/job.rb b/lib/gitlab/ci/config/entry/job.rb
index f960cec1f26..ecc2c5cb729 100644
--- a/lib/gitlab/ci/config/entry/job.rb
+++ b/lib/gitlab/ci/config/entry/job.rb
@@ -122,39 +122,9 @@ module Gitlab
:needs, :retry, :parallel, :start_in,
:interruptible, :timeout, :resource_group, :release
- Matcher = Struct.new(:name, :config) do
- def applies?
- job_is_not_hidden? &&
- config_is_a_hash? &&
- has_job_keys?
- end
-
- private
-
- def job_is_not_hidden?
- !name.to_s.start_with?('.')
- end
-
- def config_is_a_hash?
- config.is_a?(Hash)
- end
-
- def has_job_keys?
- if name == :default
- config.key?(:script)
- else
- (ALLOWED_KEYS & config.keys).any?
- end
- end
- end
-
def self.matching?(name, config)
- if Gitlab::Ci::Features.job_entry_matches_all_keys?
- Matcher.new(name, config).applies?
- else
- !name.to_s.start_with?('.') &&
- config.is_a?(Hash) && config.key?(:script)
- end
+ !name.to_s.start_with?('.') &&
+ config.is_a?(Hash) && config.key?(:script)
end
def self.visible?
diff --git a/lib/gitlab/ci/config/entry/jobs.rb b/lib/gitlab/ci/config/entry/jobs.rb
index 1d3036189b0..b5ce42969a5 100644
--- a/lib/gitlab/ci/config/entry/jobs.rb
+++ b/lib/gitlab/ci/config/entry/jobs.rb
@@ -14,8 +14,8 @@ module Gitlab
validates :config, type: Hash
validate do
- unless has_valid_jobs?
- errors.add(:config, 'should contain valid jobs')
+ each_unmatched_job do |name|
+ errors.add(name, 'config should implement a script: or a trigger: keyword')
end
unless has_visible_job?
@@ -23,9 +23,9 @@ module Gitlab
end
end
- def has_valid_jobs?
- config.all? do |name, value|
- Jobs.find_type(name, value)
+ def each_unmatched_job
+ config.each do |name, value|
+ yield(name) unless Jobs.find_type(name, value)
end
end
diff --git a/lib/gitlab/ci/config/entry/root.rb b/lib/gitlab/ci/config/entry/root.rb
index 19d6a470941..2d93f1ab06e 100644
--- a/lib/gitlab/ci/config/entry/root.rb
+++ b/lib/gitlab/ci/config/entry/root.rb
@@ -134,7 +134,7 @@ module Gitlab
@jobs_config = @config
.except(*self.class.reserved_nodes_names)
.select do |name, config|
- Entry::Jobs.find_type(name, config).present?
+ Entry::Jobs.find_type(name, config).present? || ALLOWED_KEYS.exclude?(name)
end
@config = @config.except(*@jobs_config.keys)
diff --git a/lib/gitlab/ci/config/normalizer.rb b/lib/gitlab/ci/config/normalizer.rb
index 451ba14bb89..22fcd84c968 100644
--- a/lib/gitlab/ci/config/normalizer.rb
+++ b/lib/gitlab/ci/config/normalizer.rb
@@ -11,6 +11,7 @@ module Gitlab
end
def normalize_jobs
+ return {} unless @jobs_config
return @jobs_config if parallelized_jobs.empty?
expand_parallelize_jobs do |job_name, config|
diff --git a/lib/gitlab/ci/config/normalizer/matrix_strategy.rb b/lib/gitlab/ci/config/normalizer/matrix_strategy.rb
index db21274a9ed..5a23836d8a0 100644
--- a/lib/gitlab/ci/config/normalizer/matrix_strategy.rb
+++ b/lib/gitlab/ci/config/normalizer/matrix_strategy.rb
@@ -48,14 +48,13 @@ module Gitlab
}
end
- def name_with_details
- vars = variables.map { |key, value| "#{key}=#{value}"}.join('; ')
-
- "#{job_name} (#{vars})"
- end
-
def name
- "#{job_name} #{instance}/#{total}"
+ vars = variables
+ .values
+ .compact
+ .join(', ')
+
+ "#{job_name}: [#{vars}]"
end
private
diff --git a/lib/gitlab/ci/features.rb b/lib/gitlab/ci/features.rb
index 2f6667d3600..e770187b124 100644
--- a/lib/gitlab/ci/features.rb
+++ b/lib/gitlab/ci/features.rb
@@ -31,56 +31,49 @@ module Gitlab
::Feature.enabled?(:ci_store_pipeline_messages, project, default_enabled: true)
end
- # Remove in https://gitlab.com/gitlab-org/gitlab/-/issues/227052
- def self.variables_api_filter_environment_scope?
- ::Feature.enabled?(:ci_variables_api_filter_environment_scope, default_enabled: true)
- end
-
def self.raise_job_rules_without_workflow_rules_warning?
::Feature.enabled?(:ci_raise_job_rules_without_workflow_rules_warning, default_enabled: true)
end
- def self.keep_latest_artifacts_for_ref_enabled?(project)
- ::Feature.enabled?(:keep_latest_artifacts_for_ref, project, default_enabled: false)
- end
-
- def self.destroy_only_unlocked_expired_artifacts_enabled?
- ::Feature.enabled?(:destroy_only_unlocked_expired_artifacts, default_enabled: false)
- end
-
def self.bulk_insert_on_create?(project)
::Feature.enabled?(:ci_bulk_insert_on_create, project, default_enabled: true)
end
- def self.ci_if_parenthesis_enabled?
- ::Feature.enabled?(:ci_if_parenthesis_enabled, default_enabled: true)
+ # NOTE: The feature flag `disallow_to_create_merge_request_pipelines_in_target_project`
+ # is a safe switch to disable the feature for a parituclar project when something went wrong,
+ # therefore it's not supposed to be enabled by default.
+ def self.disallow_to_create_merge_request_pipelines_in_target_project?(target_project)
+ ::Feature.enabled?(:ci_disallow_to_create_merge_request_pipelines_in_target_project, target_project)
end
- def self.allow_to_create_merge_request_pipelines_in_target_project?(target_project)
- ::Feature.enabled?(:ci_allow_to_create_merge_request_pipelines_in_target_project, target_project, default_enabled: true)
+ def self.lint_creates_pipeline_with_dry_run?(project)
+ ::Feature.enabled?(:ci_lint_creates_pipeline_with_dry_run, project, default_enabled: true)
end
- def self.ci_plan_needs_size_limit?(project)
- ::Feature.enabled?(:ci_plan_needs_size_limit, project, default_enabled: true)
+ def self.project_transactionless_destroy?(project)
+ Feature.enabled?(:project_transactionless_destroy, project, default_enabled: false)
end
- def self.job_entry_matches_all_keys?
- ::Feature.enabled?(:ci_job_entry_matches_all_keys)
+ def self.coverage_report_view?(project)
+ ::Feature.enabled?(:coverage_report_view, project, default_enabled: true)
end
- def self.lint_creates_pipeline_with_dry_run?(project)
- ::Feature.enabled?(:ci_lint_creates_pipeline_with_dry_run, project, default_enabled: true)
+ def self.child_of_child_pipeline_enabled?(project)
+ ::Feature.enabled?(:ci_child_of_child_pipeline, project, default_enabled: true)
end
- def self.reset_ci_minutes_for_all_namespaces?
- ::Feature.enabled?(:reset_ci_minutes_for_all_namespaces, default_enabled: false)
+ def self.trace_overwrite?
+ ::Feature.enabled?(:ci_trace_overwrite, type: :ops, default_enabled: false)
end
- def self.expand_names_for_cross_pipeline_artifacts?(project)
- ::Feature.enabled?(:ci_expand_names_for_cross_pipeline_artifacts, project)
+ def self.accept_trace?(project)
+ ::Feature.enabled?(:ci_enable_live_trace, project) &&
+ ::Feature.enabled?(:ci_accept_trace, project, type: :ops, default_enabled: false)
+ end
+
+ def self.new_artifact_file_reader_enabled?(project)
+ ::Feature.enabled?(:ci_new_artifact_file_reader, project, default_enabled: false)
end
end
end
end
-
-::Gitlab::Ci::Features.prepend_if_ee('::EE::Gitlab::Ci::Features')
diff --git a/lib/gitlab/ci/lint.rb b/lib/gitlab/ci/lint.rb
new file mode 100644
index 00000000000..86a9ebfa451
--- /dev/null
+++ b/lib/gitlab/ci/lint.rb
@@ -0,0 +1,108 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Ci
+ class Lint
+ class Result
+ attr_reader :jobs, :errors, :warnings
+
+ def initialize(jobs:, errors:, warnings:)
+ @jobs = jobs
+ @errors = errors
+ @warnings = warnings
+ end
+
+ def valid?
+ @errors.empty?
+ end
+ end
+
+ def initialize(project:, current_user:)
+ @project = project
+ @current_user = current_user
+ end
+
+ def validate(content, dry_run: false)
+ if dry_run && Gitlab::Ci::Features.lint_creates_pipeline_with_dry_run?(@project)
+ simulate_pipeline_creation(content)
+ else
+ static_validation(content)
+ end
+ end
+
+ private
+
+ def simulate_pipeline_creation(content)
+ pipeline = ::Ci::CreatePipelineService
+ .new(@project, @current_user, ref: @project.default_branch)
+ .execute(:push, dry_run: true, content: content)
+
+ Result.new(
+ jobs: dry_run_convert_to_jobs(pipeline.stages),
+ errors: pipeline.error_messages.map(&:content),
+ warnings: pipeline.warning_messages(limit: ::Gitlab::Ci::Warnings::MAX_LIMIT).map(&:content)
+ )
+ end
+
+ def static_validation(content)
+ result = Gitlab::Ci::YamlProcessor.new(
+ content,
+ project: @project,
+ user: @current_user,
+ sha: @project.repository.commit.sha
+ ).execute
+
+ Result.new(
+ jobs: static_validation_convert_to_jobs(result),
+ errors: result.errors,
+ warnings: result.warnings.take(::Gitlab::Ci::Warnings::MAX_LIMIT) # rubocop: disable CodeReuse/ActiveRecord
+ )
+ end
+
+ def dry_run_convert_to_jobs(stages)
+ stages.reduce([]) do |jobs, stage|
+ jobs + stage.statuses.map do |job|
+ {
+ name: job.name,
+ stage: stage.name,
+ before_script: job.options[:before_script].to_a,
+ script: job.options[:script].to_a,
+ after_script: job.options[:after_script].to_a,
+ tag_list: (job.tag_list if job.is_a?(::Ci::Build)).to_a,
+ environment: job.options.dig(:environment, :name),
+ when: job.when,
+ allow_failure: job.allow_failure
+ }
+ end
+ end
+ end
+
+ def static_validation_convert_to_jobs(result)
+ jobs = []
+ return jobs unless result.valid?
+
+ result.stages.each do |stage_name|
+ result.builds.each do |job|
+ next unless job[:stage] == stage_name
+
+ jobs << {
+ name: job[:name],
+ stage: stage_name,
+ before_script: job.dig(:options, :before_script).to_a,
+ script: job.dig(:options, :script).to_a,
+ after_script: job.dig(:options, :after_script).to_a,
+ tag_list: job[:tag_list].to_a,
+ only: job[:only],
+ except: job[:except],
+ environment: job[:environment],
+ when: job[:when],
+ allow_failure: job[:allow_failure]
+ }
+ end
+ end
+
+ jobs
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/ci/mask_secret.rb b/lib/gitlab/ci/mask_secret.rb
index 58d55b1bd6f..e5a7151b823 100644
--- a/lib/gitlab/ci/mask_secret.rb
+++ b/lib/gitlab/ci/mask_secret.rb
@@ -8,6 +8,11 @@ module Gitlab
# We assume 'value' must be mutable, given
# that frozen string is enabled.
+
+ ##
+ # TODO We need to remove this because it is going to change checksum of
+ # a trace.
+ #
value.gsub!(token, 'x' * token.length)
value
end
diff --git a/lib/gitlab/ci/pipeline/chain/build.rb b/lib/gitlab/ci/pipeline/chain/build.rb
index 4190c40eb66..9662209f88e 100644
--- a/lib/gitlab/ci/pipeline/chain/build.rb
+++ b/lib/gitlab/ci/pipeline/chain/build.rb
@@ -20,11 +20,7 @@ module Gitlab
pipeline_schedule: @command.schedule,
merge_request: @command.merge_request,
external_pull_request: @command.external_pull_request,
- variables_attributes: Array(@command.variables_attributes),
- # This should be removed and set on the database column default
- # level when the keep_latest_artifacts_for_ref feature flag is
- # removed.
- locked: ::Gitlab::Ci::Features.keep_latest_artifacts_for_ref_enabled?(@command.project) ? :artifacts_locked : :unlocked
+ variables_attributes: Array(@command.variables_attributes)
)
end
diff --git a/lib/gitlab/ci/pipeline/chain/command.rb b/lib/gitlab/ci/pipeline/chain/command.rb
index dbaa6951e64..d1882059dd8 100644
--- a/lib/gitlab/ci/pipeline/chain/command.rb
+++ b/lib/gitlab/ci/pipeline/chain/command.rb
@@ -12,7 +12,7 @@ module Gitlab
:seeds_block, :variables_attributes, :push_options,
:chat_data, :allow_mirror_update, :bridge, :content, :dry_run,
# These attributes are set by Chains during processing:
- :config_content, :config_processor, :stage_seeds
+ :config_content, :yaml_processor_result, :stage_seeds
) do
include Gitlab::Utils::StrongMemoize
diff --git a/lib/gitlab/ci/pipeline/chain/config/content/remote.rb b/lib/gitlab/ci/pipeline/chain/config/content/remote.rb
index dcc336b8929..4990a5a6eb5 100644
--- a/lib/gitlab/ci/pipeline/chain/config/content/remote.rb
+++ b/lib/gitlab/ci/pipeline/chain/config/content/remote.rb
@@ -9,7 +9,7 @@ module Gitlab
class Remote < Source
def content
strong_memoize(:content) do
- next unless ci_config_path =~ URI.regexp(%w[http https])
+ next unless ci_config_path =~ URI::DEFAULT_PARSER.make_regexp(%w[http https])
YAML.dump('include' => [{ 'remote' => ci_config_path }])
end
diff --git a/lib/gitlab/ci/pipeline/chain/config/process.rb b/lib/gitlab/ci/pipeline/chain/config/process.rb
index 2cfcb295407..8ccb33ffd34 100644
--- a/lib/gitlab/ci/pipeline/chain/config/process.rb
+++ b/lib/gitlab/ci/pipeline/chain/config/process.rb
@@ -11,20 +11,23 @@ module Gitlab
def perform!
raise ArgumentError, 'missing config content' unless @command.config_content
- @command.config_processor = ::Gitlab::Ci::YamlProcessor.new(
+ result = ::Gitlab::Ci::YamlProcessor.new(
@command.config_content, {
project: project,
sha: @pipeline.sha,
user: current_user,
parent_pipeline: parent_pipeline
}
- )
+ ).execute
+
+ add_warnings_to_pipeline(result.warnings)
- add_warnings_to_pipeline(@command.config_processor.warnings)
- rescue Gitlab::Ci::YamlProcessor::ValidationError => ex
- add_warnings_to_pipeline(ex.warnings)
+ if result.valid?
+ @command.yaml_processor_result = result
+ else
+ error(result.errors.first, config_error: true)
+ end
- error(ex.message, config_error: true)
rescue => ex
Gitlab::ErrorTracking.track_exception(ex,
project_id: project.id,
diff --git a/lib/gitlab/ci/pipeline/chain/evaluate_workflow_rules.rb b/lib/gitlab/ci/pipeline/chain/evaluate_workflow_rules.rb
index a793ae9cc24..3c910963a2a 100644
--- a/lib/gitlab/ci/pipeline/chain/evaluate_workflow_rules.rb
+++ b/lib/gitlab/ci/pipeline/chain/evaluate_workflow_rules.rb
@@ -39,7 +39,7 @@ module Gitlab
end
def workflow_config
- @command.config_processor.workflow_attributes || {}
+ @command.yaml_processor_result.workflow_attributes || {}
end
end
end
diff --git a/lib/gitlab/ci/pipeline/chain/remove_unwanted_chat_jobs.rb b/lib/gitlab/ci/pipeline/chain/remove_unwanted_chat_jobs.rb
index 9267c72efa4..71f22c52869 100644
--- a/lib/gitlab/ci/pipeline/chain/remove_unwanted_chat_jobs.rb
+++ b/lib/gitlab/ci/pipeline/chain/remove_unwanted_chat_jobs.rb
@@ -6,13 +6,13 @@ module Gitlab
module Chain
class RemoveUnwantedChatJobs < Chain::Base
def perform!
- raise ArgumentError, 'missing config processor' unless @command.config_processor
+ raise ArgumentError, 'missing YAML processor result' unless @command.yaml_processor_result
return unless pipeline.chat?
# When scheduling a chat pipeline we only want to run the build
# that matches the chat command.
- @command.config_processor.jobs.select! do |name, _|
+ @command.yaml_processor_result.jobs.select! do |name, _|
name.to_s == command.chat_data[:command].to_s
end
end
diff --git a/lib/gitlab/ci/pipeline/chain/seed.rb b/lib/gitlab/ci/pipeline/chain/seed.rb
index e48e79d561b..e10a0bc3718 100644
--- a/lib/gitlab/ci/pipeline/chain/seed.rb
+++ b/lib/gitlab/ci/pipeline/chain/seed.rb
@@ -9,7 +9,7 @@ module Gitlab
include Gitlab::Utils::StrongMemoize
def perform!
- raise ArgumentError, 'missing config processor' unless @command.config_processor
+ raise ArgumentError, 'missing YAML processor result' unless @command.yaml_processor_result
# Allocate next IID. This operation must be outside of transactions of pipeline creations.
pipeline.ensure_project_iid!
@@ -56,7 +56,7 @@ module Gitlab
end
def stages_attributes
- @command.config_processor.stages_attributes
+ @command.yaml_processor_result.stages_attributes
end
end
end
diff --git a/lib/gitlab/ci/pipeline/chain/validate/external.rb b/lib/gitlab/ci/pipeline/chain/validate/external.rb
index 24628338dd2..d056501a6d3 100644
--- a/lib/gitlab/ci/pipeline/chain/validate/external.rb
+++ b/lib/gitlab/ci/pipeline/chain/validate/external.rb
@@ -51,7 +51,7 @@ module Gitlab
def validate_service_request
Gitlab::HTTP.post(
validation_service_url, timeout: VALIDATION_REQUEST_TIMEOUT,
- body: validation_service_payload(@pipeline, @command.config_processor.stages_attributes)
+ body: validation_service_payload(@pipeline, @command.yaml_processor_result.stages_attributes)
)
end
diff --git a/lib/gitlab/ci/pipeline/expression/lexer.rb b/lib/gitlab/ci/pipeline/expression/lexer.rb
index 5b7365cb33b..ac03ef79ccb 100644
--- a/lib/gitlab/ci/pipeline/expression/lexer.rb
+++ b/lib/gitlab/ci/pipeline/expression/lexer.rb
@@ -24,26 +24,8 @@ module Gitlab
Expression::Lexeme::Or
].freeze
- # To be removed with `ci_if_parenthesis_enabled`
- LEGACY_LEXEMES = [
- Expression::Lexeme::Variable,
- Expression::Lexeme::String,
- Expression::Lexeme::Pattern,
- Expression::Lexeme::Null,
- Expression::Lexeme::Equals,
- Expression::Lexeme::Matches,
- Expression::Lexeme::NotEquals,
- Expression::Lexeme::NotMatches,
- Expression::Lexeme::And,
- Expression::Lexeme::Or
- ].freeze
-
def self.lexemes
- if ::Gitlab::Ci::Features.ci_if_parenthesis_enabled?
- LEXEMES
- else
- LEGACY_LEXEMES
- end
+ LEXEMES
end
MAX_TOKENS = 100
diff --git a/lib/gitlab/ci/pipeline/expression/parser.rb b/lib/gitlab/ci/pipeline/expression/parser.rb
index 27d7aa2f37e..a20b0015e05 100644
--- a/lib/gitlab/ci/pipeline/expression/parser.rb
+++ b/lib/gitlab/ci/pipeline/expression/parser.rb
@@ -15,12 +15,7 @@ module Gitlab
def tree
results = []
- tokens =
- if ::Gitlab::Ci::Features.ci_if_parenthesis_enabled?
- tokens_rpn
- else
- legacy_tokens_rpn
- end
+ tokens = tokens_rpn
tokens.each do |token|
case token.type
@@ -78,27 +73,6 @@ module Gitlab
output.concat(operators.reverse)
end
-
- # To be removed with `ci_if_parenthesis_enabled`
- def legacy_tokens_rpn
- output = []
- operators = []
-
- @tokens.each do |token|
- case token.type
- when :value
- output.push(token)
- when :logical_operator
- if operators.any? && token.lexeme.precedence >= operators.last.lexeme.precedence
- output.push(operators.pop)
- end
-
- operators.push(token)
- end
- end
-
- output.concat(operators.reverse)
- end
end
end
end
diff --git a/lib/gitlab/ci/pipeline/seed/build.rb b/lib/gitlab/ci/pipeline/seed/build.rb
index 3be3fa63b92..91dbcc616ea 100644
--- a/lib/gitlab/ci/pipeline/seed/build.rb
+++ b/lib/gitlab/ci/pipeline/seed/build.rb
@@ -11,8 +11,6 @@ module Gitlab
delegate :dig, to: :@seed_attributes
- DEFAULT_NEEDS_LIMIT = 10
-
def initialize(pipeline, attributes, previous_stages)
@pipeline = pipeline
@seed_attributes = attributes
@@ -140,11 +138,7 @@ module Gitlab
end
def max_needs_allowed
- if ::Gitlab::Ci::Features.ci_plan_needs_size_limit?(@pipeline.project)
- @pipeline.project.actual_limits.ci_needs_size_limit
- else
- DEFAULT_NEEDS_LIMIT
- end
+ @pipeline.project.actual_limits.ci_needs_size_limit
end
def pipeline_attributes
diff --git a/lib/gitlab/ci/pipeline_object_hierarchy.rb b/lib/gitlab/ci/pipeline_object_hierarchy.rb
new file mode 100644
index 00000000000..de3262b10e0
--- /dev/null
+++ b/lib/gitlab/ci/pipeline_object_hierarchy.rb
@@ -0,0 +1,45 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Ci
+ class PipelineObjectHierarchy < ::Gitlab::ObjectHierarchy
+ private
+
+ def middle_table
+ ::Ci::Sources::Pipeline.arel_table
+ end
+
+ def from_tables(cte)
+ [objects_table, cte.table, middle_table]
+ end
+
+ def parent_id_column(_cte)
+ middle_table[:source_pipeline_id]
+ end
+
+ def ancestor_conditions(cte)
+ middle_table[:source_pipeline_id].eq(objects_table[:id]).and(
+ middle_table[:pipeline_id].eq(cte.table[:id])
+ ).and(
+ same_project_condition
+ )
+ end
+
+ def descendant_conditions(cte)
+ middle_table[:pipeline_id].eq(objects_table[:id]).and(
+ middle_table[:source_pipeline_id].eq(cte.table[:id])
+ ).and(
+ same_project_condition
+ )
+ end
+
+ def same_project_condition
+ if options[:same_project]
+ middle_table[:source_project_id].eq(middle_table[:project_id])
+ else
+ Arel.sql('TRUE')
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/ci/reports/test_case.rb b/lib/gitlab/ci/reports/test_case.rb
index 75898745366..15a3c862c9e 100644
--- a/lib/gitlab/ci/reports/test_case.rb
+++ b/lib/gitlab/ci/reports/test_case.rb
@@ -8,7 +8,7 @@ module Gitlab
STATUS_FAILED = 'failed'
STATUS_SKIPPED = 'skipped'
STATUS_ERROR = 'error'
- STATUS_TYPES = [STATUS_SUCCESS, STATUS_FAILED, STATUS_SKIPPED, STATUS_ERROR].freeze
+ STATUS_TYPES = [STATUS_ERROR, STATUS_FAILED, STATUS_SUCCESS, STATUS_SKIPPED].freeze
attr_reader :name, :classname, :execution_time, :status, :file, :system_output, :stack_trace, :key, :attachment, :job
diff --git a/lib/gitlab/ci/reports/test_suite.rb b/lib/gitlab/ci/reports/test_suite.rb
index 5ee779227ec..e9b78b841e4 100644
--- a/lib/gitlab/ci/reports/test_suite.rb
+++ b/lib/gitlab/ci/reports/test_suite.rb
@@ -78,11 +78,27 @@ module Gitlab
end
end
+ def sorted
+ sort_by_status
+ sort_by_execution_time_desc
+ self
+ end
+
private
def existing_key?(test_case)
@test_cases[test_case.status]&.key?(test_case.key)
end
+
+ def sort_by_status
+ @test_cases = @test_cases.sort_by { |status, _| Gitlab::Ci::Reports::TestCase::STATUS_TYPES.index(status) }.to_h
+ end
+
+ def sort_by_execution_time_desc
+ @test_cases = @test_cases.keys.each_with_object({}) do |key, hash|
+ hash[key] = @test_cases[key].sort_by { |_key, test_case| -test_case.execution_time }.to_h
+ end
+ end
end
end
end
diff --git a/lib/gitlab/ci/status/bridge/common.rb b/lib/gitlab/ci/status/bridge/common.rb
index 4746195c618..b95565b5e09 100644
--- a/lib/gitlab/ci/status/bridge/common.rb
+++ b/lib/gitlab/ci/status/bridge/common.rb
@@ -10,14 +10,28 @@ module Gitlab
end
def has_details?
- false
+ !!details_path
+ end
+
+ def details_path
+ return unless Feature.enabled?(:ci_bridge_pipeline_details, subject.project, default_enabled: true)
+ return unless can?(user, :read_pipeline, downstream_pipeline)
+
+ project_pipeline_path(downstream_project, downstream_pipeline)
end
def has_action?
false
end
- def details_path
+ private
+
+ def downstream_pipeline
+ subject.downstream_pipeline
+ end
+
+ def downstream_project
+ downstream_pipeline&.project
end
end
end
diff --git a/lib/gitlab/ci/status/build/failed.rb b/lib/gitlab/ci/status/build/failed.rb
index 88846f724e7..f6562737838 100644
--- a/lib/gitlab/ci/status/build/failed.rb
+++ b/lib/gitlab/ci/status/build/failed.rb
@@ -25,7 +25,8 @@ module Gitlab
insufficient_bridge_permissions: 'no permissions to trigger downstream pipeline',
bridge_pipeline_is_child_pipeline: 'creation of child pipeline not allowed from another child pipeline',
downstream_pipeline_creation_failed: 'downstream pipeline can not be created',
- secrets_provider_not_found: 'secrets provider can not be found'
+ secrets_provider_not_found: 'secrets provider can not be found',
+ reached_max_descendant_pipelines_depth: 'reached maximum depth of child pipelines'
}.freeze
private_constant :REASONS
diff --git a/lib/gitlab/ci/status/composite.rb b/lib/gitlab/ci/status/composite.rb
index 04a9fc29802..9a4f5644f7d 100644
--- a/lib/gitlab/ci/status/composite.rb
+++ b/lib/gitlab/ci/status/composite.rb
@@ -7,7 +7,7 @@ module Gitlab
include Gitlab::Utils::StrongMemoize
# This class accepts an array of arrays/hashes/or objects
- def initialize(all_statuses, with_allow_failure: true)
+ def initialize(all_statuses, with_allow_failure: true, dag: false)
unless all_statuses.respond_to?(:pluck)
raise ArgumentError, "all_statuses needs to respond to `.pluck`"
end
@@ -15,6 +15,7 @@ module Gitlab
@status_set = Set.new
@status_key = 0
@allow_failure_key = 1 if with_allow_failure
+ @dag = dag
consume_all_statuses(all_statuses)
end
@@ -31,7 +32,13 @@ module Gitlab
return if none?
strong_memoize(:status) do
- if only_of?(:skipped, :ignored)
+ if @dag && any_of?(:skipped)
+ # The DAG job is skipped if one of the needs does not run at all.
+ 'skipped'
+ elsif @dag && !only_of?(:success, :failed, :canceled, :skipped, :success_with_warnings)
+ # DAG is blocked from executing if a dependent is not "complete"
+ 'pending'
+ elsif only_of?(:skipped, :ignored)
'skipped'
elsif only_of?(:success, :skipped, :success_with_warnings, :ignored)
'success'
diff --git a/lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml b/lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml
index 968ff0fce89..6966ce88b30 100644
--- a/lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml
@@ -150,16 +150,22 @@ workflow:
- exists:
- .static
+# NOTE: These links point to the latest templates for development in GitLab canonical project,
+# therefore the actual templates that were included for Auto DevOps pipelines
+# could be different from the contents in the links.
+# To view the actual templates, please replace `master` to the specific GitLab version when
+# the Auto DevOps pipeline started running e.g. `v13.0.2-ee`.
include:
- - template: Jobs/Build.gitlab-ci.yml # https://gitlab.com/gitlab-org/gitlab-foss/blob/master/lib/gitlab/ci/templates/Jobs/Build.gitlab-ci.yml
- - template: Jobs/Test.gitlab-ci.yml # https://gitlab.com/gitlab-org/gitlab-foss/blob/master/lib/gitlab/ci/templates/Jobs/Test.gitlab-ci.yml
- - template: Jobs/Code-Quality.gitlab-ci.yml # https://gitlab.com/gitlab-org/gitlab-foss/blob/master/lib/gitlab/ci/templates/Jobs/Code-Quality.gitlab-ci.yml
- - template: Jobs/Deploy.gitlab-ci.yml # https://gitlab.com/gitlab-org/gitlab-foss/blob/master/lib/gitlab/ci/templates/Jobs/Deploy.gitlab-ci.yml
- - template: Jobs/DAST-Default-Branch-Deploy.gitlab-ci.yml # https://gitlab.com/gitlab-org/gitlab-foss/blob/master/lib/gitlab/ci/templates/Jobs/DAST-Default-Branch-Deploy.gitlab-ci.yml
- - template: Jobs/Browser-Performance-Testing.gitlab-ci.yml # https://gitlab.com/gitlab-org/gitlab-foss/blob/master/lib/gitlab/ci/templates/Jobs/Browser-Performance-Testing.gitlab-ci.yml
- - template: Security/DAST.gitlab-ci.yml # https://gitlab.com/gitlab-org/gitlab-foss/blob/master/lib/gitlab/ci/templates/Security/DAST.gitlab-ci.yml
- - template: Security/Container-Scanning.gitlab-ci.yml # https://gitlab.com/gitlab-org/gitlab-foss/blob/master/lib/gitlab/ci/templates/Security/Container-Scanning.gitlab-ci.yml
- - template: Security/Dependency-Scanning.gitlab-ci.yml # https://gitlab.com/gitlab-org/gitlab-foss/blob/master/lib/gitlab/ci/templates/Security/Dependency-Scanning.gitlab-ci.yml
- - template: Security/License-Scanning.gitlab-ci.yml # https://gitlab.com/gitlab-org/gitlab-foss/blob/master/lib/gitlab/ci/templates/Security/License-Scanning.gitlab-ci.yml
- - template: Security/SAST.gitlab-ci.yml # https://gitlab.com/gitlab-org/gitlab-foss/blob/master/lib/gitlab/ci/templates/Security/SAST.gitlab-ci.yml
- - template: Security/Secret-Detection.gitlab-ci.yml # https://gitlab.com/gitlab-org/gitlab-foss/blob/master/lib/gitlab/ci/templates/Security/Secret-Detection.gitlab-ci.yml
+ - template: Jobs/Build.gitlab-ci.yml # https://gitlab.com/gitlab-org/gitlab/blob/master/lib/gitlab/ci/templates/Jobs/Build.gitlab-ci.yml
+ - template: Jobs/Test.gitlab-ci.yml # https://gitlab.com/gitlab-org/gitlab/blob/master/lib/gitlab/ci/templates/Jobs/Test.gitlab-ci.yml
+ - template: Jobs/Code-Quality.gitlab-ci.yml # https://gitlab.com/gitlab-org/gitlab/blob/master/lib/gitlab/ci/templates/Jobs/Code-Quality.gitlab-ci.yml
+ - template: Jobs/Deploy.gitlab-ci.yml # https://gitlab.com/gitlab-org/gitlab/blob/master/lib/gitlab/ci/templates/Jobs/Deploy.gitlab-ci.yml
+ - template: Jobs/Deploy/ECS.gitlab-ci.yml # https://gitlab.com/gitlab-org/gitlab/blob/master/lib/gitlab/ci/templates/Jobs/Deploy/ECS.gitlab-ci.yml
+ - template: Jobs/DAST-Default-Branch-Deploy.gitlab-ci.yml # https://gitlab.com/gitlab-org/gitlab/blob/master/lib/gitlab/ci/templates/Jobs/DAST-Default-Branch-Deploy.gitlab-ci.yml
+ - template: Jobs/Browser-Performance-Testing.gitlab-ci.yml # https://gitlab.com/gitlab-org/gitlab/blob/master/lib/gitlab/ci/templates/Jobs/Browser-Performance-Testing.gitlab-ci.yml
+ - template: Security/DAST.gitlab-ci.yml # https://gitlab.com/gitlab-org/gitlab/blob/master/lib/gitlab/ci/templates/Security/DAST.gitlab-ci.yml
+ - template: Security/Container-Scanning.gitlab-ci.yml # https://gitlab.com/gitlab-org/gitlab/blob/master/lib/gitlab/ci/templates/Security/Container-Scanning.gitlab-ci.yml
+ - template: Security/Dependency-Scanning.gitlab-ci.yml # https://gitlab.com/gitlab-org/gitlab/blob/master/lib/gitlab/ci/templates/Security/Dependency-Scanning.gitlab-ci.yml
+ - template: Security/License-Scanning.gitlab-ci.yml # https://gitlab.com/gitlab-org/gitlab/blob/master/lib/gitlab/ci/templates/Security/License-Scanning.gitlab-ci.yml
+ - template: Security/SAST.gitlab-ci.yml # https://gitlab.com/gitlab-org/gitlab/blob/master/lib/gitlab/ci/templates/Security/SAST.gitlab-ci.yml
+ - template: Security/Secret-Detection.gitlab-ci.yml # https://gitlab.com/gitlab-org/gitlab/blob/master/lib/gitlab/ci/templates/Security/Secret-Detection.gitlab-ci.yml
diff --git a/lib/gitlab/ci/templates/Jobs/Browser-Performance-Testing.gitlab-ci.yml b/lib/gitlab/ci/templates/Jobs/Browser-Performance-Testing.gitlab-ci.yml
index 8553a940bd7..5edb26a0b56 100644
--- a/lib/gitlab/ci/templates/Jobs/Browser-Performance-Testing.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Jobs/Browser-Performance-Testing.gitlab-ci.yml
@@ -7,7 +7,7 @@ performance:
variables:
DOCKER_TLS_CERTDIR: ""
SITESPEED_IMAGE: sitespeedio/sitespeed.io
- SITESPEED_VERSION: 13.3.0
+ SITESPEED_VERSION: 14.1.0
SITESPEED_OPTIONS: ''
services:
- docker:19.03.12-dind
@@ -20,15 +20,15 @@ performance:
fi
- export CI_ENVIRONMENT_URL=$(cat environment_url.txt)
- mkdir gitlab-exporter
- - wget -O gitlab-exporter/index.js https://gitlab.com/gitlab-org/gl-performance/raw/1.0.1/index.js
+ - wget -O gitlab-exporter/index.js https://gitlab.com/gitlab-org/gl-performance/raw/1.1.0/index.js
- mkdir sitespeed-results
- |
if [ -f .gitlab-urls.txt ]
then
sed -i -e 's@^@'"$CI_ENVIRONMENT_URL"'@' .gitlab-urls.txt
- docker run --shm-size=1g --rm -v "$(pwd)":/sitespeed.io $SITESPEED_IMAGE:$SITESPEED_VERSION --plugins.add ./gitlab-exporter --outputFolder sitespeed-results .gitlab-urls.txt $SITESPEED_OPTIONS
+ docker run --shm-size=1g --rm -v "$(pwd)":/sitespeed.io $SITESPEED_IMAGE:$SITESPEED_VERSION --plugins.add ./gitlab-exporter --cpu --outputFolder sitespeed-results .gitlab-urls.txt $SITESPEED_OPTIONS
else
- docker run --shm-size=1g --rm -v "$(pwd)":/sitespeed.io $SITESPEED_IMAGE:$SITESPEED_VERSION --plugins.add ./gitlab-exporter --outputFolder sitespeed-results "$CI_ENVIRONMENT_URL" $SITESPEED_OPTIONS
+ docker run --shm-size=1g --rm -v "$(pwd)":/sitespeed.io $SITESPEED_IMAGE:$SITESPEED_VERSION --plugins.add ./gitlab-exporter --cpu --outputFolder sitespeed-results "$CI_ENVIRONMENT_URL" $SITESPEED_OPTIONS
fi
- mv sitespeed-results/data/performance.json browser-performance.json
artifacts:
diff --git a/lib/gitlab/ci/templates/Jobs/Code-Quality.gitlab-ci.yml b/lib/gitlab/ci/templates/Jobs/Code-Quality.gitlab-ci.yml
index cf851c875ee..568ceceeaa2 100644
--- a/lib/gitlab/ci/templates/Jobs/Code-Quality.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Jobs/Code-Quality.gitlab-ci.yml
@@ -9,6 +9,8 @@ code_quality:
DOCKER_TLS_CERTDIR: ""
CODE_QUALITY_IMAGE: "registry.gitlab.com/gitlab-org/ci-cd/codequality:0.85.10-gitlab.1"
needs: []
+ before_script:
+ - export SOURCE_CODE=$PWD
script:
- |
if ! docker info &>/dev/null; then
@@ -16,11 +18,27 @@ code_quality:
export DOCKER_HOST='tcp://localhost:2375'
fi
fi
+ - | # this is required to avoid undesirable reset of Docker image ENV variables being set on build stage
+ function propagate_env_vars() {
+ CURRENT_ENV=$(printenv)
+
+ for VAR_NAME; do
+ echo $CURRENT_ENV | grep "${VAR_NAME}=" > /dev/null && echo "--env $VAR_NAME "
+ done
+ }
- docker pull --quiet "$CODE_QUALITY_IMAGE"
- - docker run
- --env SOURCE_CODE="$PWD"
- --volume "$PWD":/code
- --volume /var/run/docker.sock:/var/run/docker.sock
+ - |
+ docker run \
+ $(propagate_env_vars \
+ SOURCE_CODE \
+ TIMEOUT_SECONDS \
+ CODECLIMATE_DEBUG \
+ CODECLIMATE_DEV \
+ REPORT_STDOUT \
+ ENGINE_MEMORY_LIMIT_BYTES \
+ ) \
+ --volume "$PWD":/code \
+ --volume /var/run/docker.sock:/var/run/docker.sock \
"$CODE_QUALITY_IMAGE" /code
artifacts:
reports:
diff --git a/lib/gitlab/ci/templates/Jobs/Deploy.gitlab-ci.yml b/lib/gitlab/ci/templates/Jobs/Deploy.gitlab-ci.yml
index 2922e1c6e88..829fd7a722f 100644
--- a/lib/gitlab/ci/templates/Jobs/Deploy.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Jobs/Deploy.gitlab-ci.yml
@@ -2,9 +2,6 @@
image: "registry.gitlab.com/gitlab-org/cluster-integration/auto-deploy-image:v1.0.3"
dependencies: []
-include:
- - template: Jobs/Deploy/ECS.gitlab-ci.yml
-
review:
extends: .auto-deploy
stage: review
diff --git a/lib/gitlab/ci/templates/Jobs/Deploy.latest.gitlab-ci.yml b/lib/gitlab/ci/templates/Jobs/Deploy.latest.gitlab-ci.yml
new file mode 100644
index 00000000000..829fd7a722f
--- /dev/null
+++ b/lib/gitlab/ci/templates/Jobs/Deploy.latest.gitlab-ci.yml
@@ -0,0 +1,249 @@
+.auto-deploy:
+ image: "registry.gitlab.com/gitlab-org/cluster-integration/auto-deploy-image:v1.0.3"
+ dependencies: []
+
+review:
+ extends: .auto-deploy
+ stage: review
+ script:
+ - auto-deploy check_kube_domain
+ - auto-deploy download_chart
+ - auto-deploy ensure_namespace
+ - auto-deploy initialize_tiller
+ - auto-deploy create_secret
+ - auto-deploy deploy
+ - auto-deploy persist_environment_url
+ environment:
+ name: review/$CI_COMMIT_REF_NAME
+ url: http://$CI_PROJECT_ID-$CI_ENVIRONMENT_SLUG.$KUBE_INGRESS_BASE_DOMAIN
+ on_stop: stop_review
+ artifacts:
+ paths: [environment_url.txt, tiller.log]
+ when: always
+ rules:
+ - if: '$CI_KUBERNETES_ACTIVE == null || $CI_KUBERNETES_ACTIVE == ""'
+ when: never
+ - if: '$CI_COMMIT_BRANCH == "master"'
+ when: never
+ - if: '$REVIEW_DISABLED'
+ when: never
+ - if: '$CI_COMMIT_TAG || $CI_COMMIT_BRANCH'
+
+stop_review:
+ extends: .auto-deploy
+ stage: cleanup
+ variables:
+ GIT_STRATEGY: none
+ script:
+ - auto-deploy initialize_tiller
+ - auto-deploy delete
+ environment:
+ name: review/$CI_COMMIT_REF_NAME
+ action: stop
+ allow_failure: true
+ rules:
+ - if: '$CI_KUBERNETES_ACTIVE == null || $CI_KUBERNETES_ACTIVE == ""'
+ when: never
+ - if: '$CI_COMMIT_BRANCH == "master"'
+ when: never
+ - if: '$REVIEW_DISABLED'
+ when: never
+ - if: '$CI_COMMIT_TAG || $CI_COMMIT_BRANCH'
+ when: manual
+
+# Staging deploys are disabled by default since
+# continuous deployment to production is enabled by default
+# If you prefer to automatically deploy to staging and
+# only manually promote to production, enable this job by setting
+# STAGING_ENABLED.
+
+staging:
+ extends: .auto-deploy
+ stage: staging
+ script:
+ - auto-deploy check_kube_domain
+ - auto-deploy download_chart
+ - auto-deploy ensure_namespace
+ - auto-deploy initialize_tiller
+ - auto-deploy create_secret
+ - auto-deploy deploy
+ environment:
+ name: staging
+ url: http://$CI_PROJECT_PATH_SLUG-staging.$KUBE_INGRESS_BASE_DOMAIN
+ rules:
+ - if: '$CI_KUBERNETES_ACTIVE == null || $CI_KUBERNETES_ACTIVE == ""'
+ when: never
+ - if: '$CI_COMMIT_BRANCH != "master"'
+ when: never
+ - if: '$STAGING_ENABLED'
+
+# Canaries are disabled by default, but if you want them,
+# and know what the downsides are, you can enable this by setting
+# CANARY_ENABLED.
+
+canary:
+ extends: .auto-deploy
+ stage: canary
+ allow_failure: true
+ script:
+ - auto-deploy check_kube_domain
+ - auto-deploy download_chart
+ - auto-deploy ensure_namespace
+ - auto-deploy initialize_tiller
+ - auto-deploy create_secret
+ - auto-deploy deploy canary
+ environment:
+ name: production
+ url: http://$CI_PROJECT_PATH_SLUG.$KUBE_INGRESS_BASE_DOMAIN
+ rules:
+ - if: '$CI_KUBERNETES_ACTIVE == null || $CI_KUBERNETES_ACTIVE == ""'
+ when: never
+ - if: '$CI_COMMIT_BRANCH != "master"'
+ when: never
+ - if: '$CANARY_ENABLED'
+ when: manual
+
+.production: &production_template
+ extends: .auto-deploy
+ stage: production
+ script:
+ - auto-deploy check_kube_domain
+ - auto-deploy download_chart
+ - auto-deploy ensure_namespace
+ - auto-deploy initialize_tiller
+ - auto-deploy create_secret
+ - auto-deploy deploy
+ - auto-deploy delete canary
+ - auto-deploy delete rollout
+ - auto-deploy persist_environment_url
+ environment:
+ name: production
+ url: http://$CI_PROJECT_PATH_SLUG.$KUBE_INGRESS_BASE_DOMAIN
+ artifacts:
+ paths: [environment_url.txt, tiller.log]
+ when: always
+
+production:
+ <<: *production_template
+ rules:
+ - if: '$CI_KUBERNETES_ACTIVE == null || $CI_KUBERNETES_ACTIVE == ""'
+ when: never
+ - if: '$STAGING_ENABLED'
+ when: never
+ - if: '$CANARY_ENABLED'
+ when: never
+ - if: '$INCREMENTAL_ROLLOUT_ENABLED'
+ when: never
+ - if: '$INCREMENTAL_ROLLOUT_MODE'
+ when: never
+ - if: '$CI_COMMIT_BRANCH == "master"'
+
+production_manual:
+ <<: *production_template
+ allow_failure: false
+ rules:
+ - if: '$CI_KUBERNETES_ACTIVE == null || $CI_KUBERNETES_ACTIVE == ""'
+ when: never
+ - if: '$INCREMENTAL_ROLLOUT_ENABLED'
+ when: never
+ - if: '$INCREMENTAL_ROLLOUT_MODE'
+ when: never
+ - if: '$CI_COMMIT_BRANCH == "master" && $STAGING_ENABLED'
+ when: manual
+ - if: '$CI_COMMIT_BRANCH == "master" && $CANARY_ENABLED'
+ when: manual
+
+# This job implements incremental rollout on for every push to `master`.
+
+.rollout: &rollout_template
+ extends: .auto-deploy
+ script:
+ - auto-deploy check_kube_domain
+ - auto-deploy download_chart
+ - auto-deploy ensure_namespace
+ - auto-deploy initialize_tiller
+ - auto-deploy create_secret
+ - auto-deploy deploy rollout $ROLLOUT_PERCENTAGE
+ - auto-deploy scale stable $((100-ROLLOUT_PERCENTAGE))
+ - auto-deploy delete canary
+ - auto-deploy persist_environment_url
+ environment:
+ name: production
+ url: http://$CI_PROJECT_PATH_SLUG.$KUBE_INGRESS_BASE_DOMAIN
+ artifacts:
+ paths: [environment_url.txt, tiller.log]
+ when: always
+
+.manual_rollout_template: &manual_rollout_template
+ <<: *rollout_template
+ stage: production
+ resource_group: production
+ allow_failure: true
+ rules:
+ - if: '$CI_KUBERNETES_ACTIVE == null || $CI_KUBERNETES_ACTIVE == ""'
+ when: never
+ - if: '$INCREMENTAL_ROLLOUT_MODE == "timed"'
+ when: never
+ - if: '$CI_COMMIT_BRANCH != "master"'
+ when: never
+ # $INCREMENTAL_ROLLOUT_ENABLED is for compamtibilty with pre-GitLab 11.4 syntax
+ - if: '$INCREMENTAL_ROLLOUT_MODE == "manual" || $INCREMENTAL_ROLLOUT_ENABLED'
+ when: manual
+
+.timed_rollout_template: &timed_rollout_template
+ <<: *rollout_template
+ rules:
+ - if: '$CI_KUBERNETES_ACTIVE == null || $CI_KUBERNETES_ACTIVE == ""'
+ when: never
+ - if: '$INCREMENTAL_ROLLOUT_MODE == "manual"'
+ when: never
+ - if: '$CI_COMMIT_BRANCH != "master"'
+ when: never
+ - if: '$INCREMENTAL_ROLLOUT_MODE == "timed"'
+ when: delayed
+ start_in: 5 minutes
+
+timed rollout 10%:
+ <<: *timed_rollout_template
+ stage: incremental rollout 10%
+ variables:
+ ROLLOUT_PERCENTAGE: 10
+
+timed rollout 25%:
+ <<: *timed_rollout_template
+ stage: incremental rollout 25%
+ variables:
+ ROLLOUT_PERCENTAGE: 25
+
+timed rollout 50%:
+ <<: *timed_rollout_template
+ stage: incremental rollout 50%
+ variables:
+ ROLLOUT_PERCENTAGE: 50
+
+timed rollout 100%:
+ <<: *timed_rollout_template
+ <<: *production_template
+ stage: incremental rollout 100%
+ variables:
+ ROLLOUT_PERCENTAGE: 100
+
+rollout 10%:
+ <<: *manual_rollout_template
+ variables:
+ ROLLOUT_PERCENTAGE: 10
+
+rollout 25%:
+ <<: *manual_rollout_template
+ variables:
+ ROLLOUT_PERCENTAGE: 25
+
+rollout 50%:
+ <<: *manual_rollout_template
+ variables:
+ ROLLOUT_PERCENTAGE: 50
+
+rollout 100%:
+ <<: *manual_rollout_template
+ <<: *production_template
+ allow_failure: false
diff --git a/lib/gitlab/ci/templates/Jobs/Load-Performance-Testing.gitlab-ci.yml b/lib/gitlab/ci/templates/Jobs/Load-Performance-Testing.gitlab-ci.yml
index 4a9849c85c9..9a7c513c25f 100644
--- a/lib/gitlab/ci/templates/Jobs/Load-Performance-Testing.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Jobs/Load-Performance-Testing.gitlab-ci.yml
@@ -8,6 +8,7 @@ load_performance:
K6_VERSION: 0.27.0
K6_TEST_FILE: github.com/loadimpact/k6/samples/http_get.js
K6_OPTIONS: ''
+ K6_DOCKER_OPTIONS: ''
services:
- docker:19.03.11-dind
script:
@@ -17,7 +18,7 @@ load_performance:
export DOCKER_HOST='tcp://localhost:2375'
fi
fi
- - docker run --rm -v "$(pwd)":/k6 -w /k6 $K6_IMAGE:$K6_VERSION run $K6_TEST_FILE --summary-export=load-performance.json $K6_OPTIONS
+ - docker run --rm -v "$(pwd)":/k6 -w /k6 $K6_DOCKER_OPTIONS $K6_IMAGE:$K6_VERSION run $K6_TEST_FILE --summary-export=load-performance.json $K6_OPTIONS
artifacts:
reports:
load_performance: load-performance.json
diff --git a/lib/gitlab/ci/templates/Managed-Cluster-Applications.gitlab-ci.yml b/lib/gitlab/ci/templates/Managed-Cluster-Applications.gitlab-ci.yml
index 3d0bacda853..7050b41e045 100644
--- a/lib/gitlab/ci/templates/Managed-Cluster-Applications.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Managed-Cluster-Applications.gitlab-ci.yml
@@ -1,27 +1,11 @@
apply:
stage: deploy
- image: "registry.gitlab.com/gitlab-org/cluster-integration/cluster-applications:v0.24.2"
+ image: "registry.gitlab.com/gitlab-org/cluster-integration/cluster-applications:v0.29.0"
environment:
name: production
variables:
TILLER_NAMESPACE: gitlab-managed-apps
GITLAB_MANAGED_APPS_FILE: $CI_PROJECT_DIR/.gitlab/managed-apps/config.yaml
- INGRESS_VALUES_FILE: $CI_PROJECT_DIR/.gitlab/managed-apps/ingress/values.yaml
- CERT_MANAGER_VALUES_FILE: $CI_PROJECT_DIR/.gitlab/managed-apps/cert-manager/values.yaml
- SENTRY_VALUES_FILE: $CI_PROJECT_DIR/.gitlab/managed-apps/sentry/values.yaml
- GITLAB_RUNNER_VALUES_FILE: $CI_PROJECT_DIR/.gitlab/managed-apps/gitlab-runner/values.yaml
- CILIUM_VALUES_FILE: $CI_PROJECT_DIR/.gitlab/managed-apps/cilium/values.yaml
- CILIUM_HUBBLE_VALUES_FILE: $CI_PROJECT_DIR/.gitlab/managed-apps/cilium/hubble-values.yaml
- JUPYTERHUB_VALUES_FILE: $CI_PROJECT_DIR/.gitlab/managed-apps/jupyterhub/values.yaml
- PROMETHEUS_VALUES_FILE: $CI_PROJECT_DIR/.gitlab/managed-apps/prometheus/values.yaml
- ELASTIC_STACK_VALUES_FILE: $CI_PROJECT_DIR/.gitlab/managed-apps/elastic-stack/values.yaml
- VAULT_VALUES_FILE: $CI_PROJECT_DIR/.gitlab/managed-apps/vault/values.yaml
- CROSSPLANE_VALUES_FILE: $CI_PROJECT_DIR/.gitlab/managed-apps/crossplane/values.yaml
- FLUENTD_VALUES_FILE: $CI_PROJECT_DIR/.gitlab/managed-apps/fluentd/values.yaml
- KNATIVE_VALUES_FILE: $CI_PROJECT_DIR/.gitlab/managed-apps/knative/values.yaml
- POSTHOG_VALUES_FILE: $CI_PROJECT_DIR/.gitlab/managed-apps/posthog/values.yaml
- FALCO_VALUES_FILE: $CI_PROJECT_DIR/.gitlab/managed-apps/falco/values.yaml
- APPARMOR_VALUES_FILE: $CI_PROJECT_DIR/.gitlab/managed-apps/apparmor/values.yaml
script:
- gitlab-managed-apps /usr/local/share/gitlab-managed-apps/helmfile.yaml
only:
diff --git a/lib/gitlab/ci/templates/Security/API-Fuzzing.gitlab-ci.yml b/lib/gitlab/ci/templates/Security/API-Fuzzing.gitlab-ci.yml
index e87f0f28d01..c3a92b67a8b 100644
--- a/lib/gitlab/ci/templates/Security/API-Fuzzing.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Security/API-Fuzzing.gitlab-ci.yml
@@ -37,9 +37,6 @@ apifuzzer_fuzz:
$FUZZAPI_OPENAPI == null &&
$FUZZAPI_D_WORKER_IMAGE == null
when: never
- - if: $FUZZAPI_D_WORKER_IMAGE == null &&
- $FUZZAPI_TARGET_URL == null
- when: never
- if: $GITLAB_FEATURES =~ /\bapi_fuzzing\b/
services:
- docker:19.03.12-dind
@@ -74,13 +71,15 @@ apifuzzer_fuzz:
-e FUZZAPI_TIMEOUT \
-e FUZZAPI_VERBOSE \
-e FUZZAPI_SERVICE_START_TIMEOUT \
+ -e FUZZAPI_HTTP_USERNAME \
+ -e FUZZAPI_HTTP_PASSWORD \
-e GITLAB_FEATURES \
-v $CI_PROJECT_DIR:/app \
-p 80:80 \
-p 8000:8000 \
-p 514:514 \
--restart=no \
- registry.gitlab.com/gitlab-org/security-products/analyzers/api-fuzzing-src:${FUZZAPI_VERSION}-engine
+ registry.gitlab.com/gitlab-org/security-products/analyzers/api-fuzzing:${FUZZAPI_VERSION}-engine
#
# Start target container
- |
@@ -119,6 +118,9 @@ apifuzzer_fuzz:
# Wait for testing to complete if api fuzzer is scanning
- if [ "$FUZZAPI_HAR$FUZZAPI_OPENAPI" != "" ]; then echo "Waiting for API Fuzzer to exit"; docker wait apifuzzer; fi
#
+ # Propagate exit code from api fuzzer (if any)
+ - if [[ $(docker inspect apifuzzer --format='{{.State.ExitCode}}') != "0" ]]; then echo "API Fuzzing exited with an error. Logs are available as job artifacts."; docker logs apifuzzer; exit 1; fi
+ #
# Run user provided pre-script
- sh -c "$FUZZAPI_POST_SCRIPT"
#
diff --git a/lib/gitlab/ci/templates/Security/Coverage-Fuzzing.gitlab-ci.yml b/lib/gitlab/ci/templates/Security/Coverage-Fuzzing.gitlab-ci.yml
index 3f47e575afd..4b957a8f771 100644
--- a/lib/gitlab/ci/templates/Security/Coverage-Fuzzing.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Security/Coverage-Fuzzing.gitlab-ci.yml
@@ -34,5 +34,5 @@ variables:
rules:
- if: $COVFUZZ_DISABLED
when: never
- - if: $GITLAB_FEATURES =~ /\bcoverage_fuzzing\b/
+ - if: $CI_COMMIT_BRANCH && $GITLAB_FEATURES =~ /\bcoverage_fuzzing\b/
- if: $CI_RUNNER_EXECUTABLE_ARCH == "linux"
diff --git a/lib/gitlab/ci/templates/Security/Dependency-Scanning.gitlab-ci.yml b/lib/gitlab/ci/templates/Security/Dependency-Scanning.gitlab-ci.yml
index d5275c57ef8..3789f0edc1c 100644
--- a/lib/gitlab/ci/templates/Security/Dependency-Scanning.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Security/Dependency-Scanning.gitlab-ci.yml
@@ -12,81 +12,24 @@ variables:
DS_DEFAULT_ANALYZERS: "bundler-audit, retire.js, gemnasium, gemnasium-maven, gemnasium-python"
DS_EXCLUDED_PATHS: "spec, test, tests, tmp"
DS_MAJOR_VERSION: 2
- DS_DISABLE_DIND: "true"
dependency_scanning:
stage: test
- image: docker:stable
- variables:
- DOCKER_DRIVER: overlay2
- DOCKER_TLS_CERTDIR: ""
- allow_failure: true
- services:
- - docker:stable-dind
script:
- - |
- if ! docker info &>/dev/null; then
- if [ -z "$DOCKER_HOST" -a "$KUBERNETES_PORT" ]; then
- export DOCKER_HOST='tcp://localhost:2375'
- fi
- fi
- - | # this is required to avoid undesirable reset of Docker image ENV variables being set on build stage
- function propagate_env_vars() {
- CURRENT_ENV=$(printenv)
-
- for VAR_NAME; do
- echo $CURRENT_ENV | grep "${VAR_NAME}=" > /dev/null && echo "--env $VAR_NAME "
- done
- }
- - |
- docker run \
- $(propagate_env_vars \
- DS_ANALYZER_IMAGES \
- SECURE_ANALYZERS_PREFIX \
- DS_ANALYZER_IMAGE_TAG \
- DS_DEFAULT_ANALYZERS \
- DS_EXCLUDED_PATHS \
- DS_DOCKER_CLIENT_NEGOTIATION_TIMEOUT \
- DS_PULL_ANALYZER_IMAGE_TIMEOUT \
- DS_RUN_ANALYZER_TIMEOUT \
- DS_PYTHON_VERSION \
- DS_PIP_VERSION \
- DS_PIP_DEPENDENCY_PATH \
- DS_JAVA_VERSION \
- GEMNASIUM_DB_LOCAL_PATH \
- GEMNASIUM_DB_REMOTE_URL \
- GEMNASIUM_DB_REF_NAME \
- PIP_INDEX_URL \
- PIP_EXTRA_INDEX_URL \
- PIP_REQUIREMENTS_FILE \
- MAVEN_CLI_OPTS \
- GRADLE_CLI_OPTS \
- SBT_CLI_OPTS \
- BUNDLER_AUDIT_UPDATE_DISABLED \
- BUNDLER_AUDIT_ADVISORY_DB_URL \
- BUNDLER_AUDIT_ADVISORY_DB_REF_NAME \
- RETIREJS_JS_ADVISORY_DB \
- RETIREJS_NODE_ADVISORY_DB \
- DS_REMEDIATE \
- ) \
- --volume "$PWD:/code" \
- --volume /var/run/docker.sock:/var/run/docker.sock \
- "registry.gitlab.com/gitlab-org/security-products/dependency-scanning:$DS_MAJOR_VERSION" /code
+ - echo "$CI_JOB_NAME is used for configuration only, and its script should not be executed"
+ - exit 1
artifacts:
reports:
dependency_scanning: gl-dependency-scanning-report.json
dependencies: []
rules:
- - if: $DEPENDENCY_SCANNING_DISABLED || $DS_DISABLE_DIND == 'true'
- when: never
- - if: $CI_COMMIT_BRANCH &&
- $GITLAB_FEATURES =~ /\bdependency_scanning\b/
+ - when: never
.ds-analyzer:
extends: dependency_scanning
- services: []
+ allow_failure: true
rules:
- - if: $DEPENDENCY_SCANNING_DISABLED || $DS_DISABLE_DIND == 'false'
+ - if: $DEPENDENCY_SCANNING_DISABLED
when: never
- if: $CI_COMMIT_BRANCH &&
$GITLAB_FEATURES =~ /\bdependency_scanning\b/
@@ -96,9 +39,11 @@ dependency_scanning:
gemnasium-dependency_scanning:
extends: .ds-analyzer
image:
- name: "$SECURE_ANALYZERS_PREFIX/gemnasium:$DS_MAJOR_VERSION"
+ name: "$DS_ANALYZER_IMAGE"
+ variables:
+ DS_ANALYZER_IMAGE: "$SECURE_ANALYZERS_PREFIX/gemnasium:$DS_MAJOR_VERSION"
rules:
- - if: $DEPENDENCY_SCANNING_DISABLED || $DS_DISABLE_DIND == 'false'
+ - if: $DEPENDENCY_SCANNING_DISABLED
when: never
- if: $CI_COMMIT_BRANCH &&
$GITLAB_FEATURES =~ /\bdependency_scanning\b/ &&
@@ -112,13 +57,16 @@ gemnasium-dependency_scanning:
- '{package-lock.json,*/package-lock.json,*/*/package-lock.json}'
- '{yarn.lock,*/yarn.lock,*/*/yarn.lock}'
- '{packages.lock.json,*/packages.lock.json,*/*/packages.lock.json}'
+ - '{conan.lock,*/conan.lock,*/*/conan.lock}'
gemnasium-maven-dependency_scanning:
extends: .ds-analyzer
image:
- name: "$SECURE_ANALYZERS_PREFIX/gemnasium-maven:$DS_MAJOR_VERSION"
+ name: "$DS_ANALYZER_IMAGE"
+ variables:
+ DS_ANALYZER_IMAGE: "$SECURE_ANALYZERS_PREFIX/gemnasium-maven:$DS_MAJOR_VERSION"
rules:
- - if: $DEPENDENCY_SCANNING_DISABLED || $DS_DISABLE_DIND == 'false'
+ - if: $DEPENDENCY_SCANNING_DISABLED
when: never
- if: $CI_COMMIT_BRANCH &&
$GITLAB_FEATURES =~ /\bdependency_scanning\b/ &&
@@ -132,9 +80,11 @@ gemnasium-maven-dependency_scanning:
gemnasium-python-dependency_scanning:
extends: .ds-analyzer
image:
- name: "$SECURE_ANALYZERS_PREFIX/gemnasium-python:$DS_MAJOR_VERSION"
+ name: "$DS_ANALYZER_IMAGE"
+ variables:
+ DS_ANALYZER_IMAGE: "$SECURE_ANALYZERS_PREFIX/gemnasium-python:$DS_MAJOR_VERSION"
rules:
- - if: $DEPENDENCY_SCANNING_DISABLED || $DS_DISABLE_DIND == 'false'
+ - if: $DEPENDENCY_SCANNING_DISABLED
when: never
- if: $CI_COMMIT_BRANCH &&
$GITLAB_FEATURES =~ /\bdependency_scanning\b/ &&
@@ -155,9 +105,11 @@ gemnasium-python-dependency_scanning:
bundler-audit-dependency_scanning:
extends: .ds-analyzer
image:
- name: "$SECURE_ANALYZERS_PREFIX/bundler-audit:$DS_MAJOR_VERSION"
+ name: "$DS_ANALYZER_IMAGE"
+ variables:
+ DS_ANALYZER_IMAGE: "$SECURE_ANALYZERS_PREFIX/bundler-audit:$DS_MAJOR_VERSION"
rules:
- - if: $DEPENDENCY_SCANNING_DISABLED || $DS_DISABLE_DIND == 'false'
+ - if: $DEPENDENCY_SCANNING_DISABLED
when: never
- if: $CI_COMMIT_BRANCH &&
$GITLAB_FEATURES =~ /\bdependency_scanning\b/ &&
@@ -168,9 +120,11 @@ bundler-audit-dependency_scanning:
retire-js-dependency_scanning:
extends: .ds-analyzer
image:
- name: "$SECURE_ANALYZERS_PREFIX/retire.js:$DS_MAJOR_VERSION"
+ name: "$DS_ANALYZER_IMAGE"
+ variables:
+ DS_ANALYZER_IMAGE: "$SECURE_ANALYZERS_PREFIX/retire.js:$DS_MAJOR_VERSION"
rules:
- - if: $DEPENDENCY_SCANNING_DISABLED || $DS_DISABLE_DIND == 'false'
+ - if: $DEPENDENCY_SCANNING_DISABLED
when: never
- if: $CI_COMMIT_BRANCH &&
$GITLAB_FEATURES =~ /\bdependency_scanning\b/ &&
diff --git a/lib/gitlab/ci/templates/Security/SAST.gitlab-ci.yml b/lib/gitlab/ci/templates/Security/SAST.gitlab-ci.yml
index 6eb17341472..77ea11d01d1 100644
--- a/lib/gitlab/ci/templates/Security/SAST.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Security/SAST.gitlab-ci.yml
@@ -9,48 +9,29 @@ variables:
# (SAST, Dependency Scanning, ...)
SECURE_ANALYZERS_PREFIX: "registry.gitlab.com/gitlab-org/security-products/analyzers"
- SAST_DEFAULT_ANALYZERS: "bandit, brakeman, gosec, spotbugs, flawfinder, phpcs-security-audit, security-code-scan, nodejs-scan, eslint, secrets, sobelow, pmd-apex, kubesec"
+ SAST_DEFAULT_ANALYZERS: "bandit, brakeman, gosec, spotbugs, flawfinder, phpcs-security-audit, security-code-scan, nodejs-scan, eslint, sobelow, pmd-apex, kubesec"
SAST_EXCLUDED_PATHS: "spec, test, tests, tmp"
SAST_ANALYZER_IMAGE_TAG: 2
- SAST_DISABLE_DIND: "true"
SCAN_KUBERNETES_MANIFESTS: "false"
sast:
stage: test
- allow_failure: true
artifacts:
reports:
sast: gl-sast-report.json
rules:
- - if: $SAST_DISABLED || $SAST_DISABLE_DIND == 'true'
- when: never
- - if: $CI_COMMIT_BRANCH && $GITLAB_FEATURES =~ /\bsast\b/
- image: docker:stable
+ - when: never
variables:
SEARCH_MAX_DEPTH: 4
- DOCKER_DRIVER: overlay2
- DOCKER_TLS_CERTDIR: ""
- services:
- - docker:stable-dind
script:
- - |
- if ! docker info &>/dev/null; then
- if [ -z "$DOCKER_HOST" -a "$KUBERNETES_PORT" ]; then
- export DOCKER_HOST='tcp://localhost:2375'
- fi
- fi
- - |
- docker run \
- $(awk 'BEGIN{for(v in ENVIRON) print v}' | grep -v -E '^(DOCKER_|CI|GITLAB_|FF_|HOME|PWD|OLDPWD|PATH|SHLVL|HOSTNAME)' | awk '{printf " -e %s", $0}') \
- --volume "$PWD:/code" \
- --volume /var/run/docker.sock:/var/run/docker.sock \
- "registry.gitlab.com/gitlab-org/security-products/sast:$SAST_ANALYZER_IMAGE_TAG" /app/bin/run /code
+ - echo "$CI_JOB_NAME is used for configuration only, and its script should not be executed"
+ - exit 1
.sast-analyzer:
extends: sast
- services: []
+ allow_failure: true
rules:
- - if: $SAST_DISABLED || $SAST_DISABLE_DIND == 'false'
+ - if: $SAST_DISABLED
when: never
- if: $CI_COMMIT_BRANCH
script:
@@ -59,9 +40,11 @@ sast:
bandit-sast:
extends: .sast-analyzer
image:
- name: "$SECURE_ANALYZERS_PREFIX/bandit:$SAST_ANALYZER_IMAGE_TAG"
+ name: "$SAST_ANALYZER_IMAGE"
+ variables:
+ SAST_ANALYZER_IMAGE: "$SECURE_ANALYZERS_PREFIX/bandit:$SAST_ANALYZER_IMAGE_TAG"
rules:
- - if: $SAST_DISABLED || $SAST_DISABLE_DIND == 'false'
+ - if: $SAST_DISABLED
when: never
- if: $CI_COMMIT_BRANCH &&
$SAST_DEFAULT_ANALYZERS =~ /bandit/
@@ -71,9 +54,11 @@ bandit-sast:
brakeman-sast:
extends: .sast-analyzer
image:
- name: "$SECURE_ANALYZERS_PREFIX/brakeman:$SAST_ANALYZER_IMAGE_TAG"
+ name: "$SAST_ANALYZER_IMAGE"
+ variables:
+ SAST_ANALYZER_IMAGE: "$SECURE_ANALYZERS_PREFIX/brakeman:$SAST_ANALYZER_IMAGE_TAG"
rules:
- - if: $SAST_DISABLED || $SAST_DISABLE_DIND == 'false'
+ - if: $SAST_DISABLED
when: never
- if: $CI_COMMIT_BRANCH &&
$SAST_DEFAULT_ANALYZERS =~ /brakeman/
@@ -83,9 +68,11 @@ brakeman-sast:
eslint-sast:
extends: .sast-analyzer
image:
- name: "$SECURE_ANALYZERS_PREFIX/eslint:$SAST_ANALYZER_IMAGE_TAG"
+ name: "$SAST_ANALYZER_IMAGE"
+ variables:
+ SAST_ANALYZER_IMAGE: "$SECURE_ANALYZERS_PREFIX/eslint:$SAST_ANALYZER_IMAGE_TAG"
rules:
- - if: $SAST_DISABLED || $SAST_DISABLE_DIND == 'false'
+ - if: $SAST_DISABLED
when: never
- if: $CI_COMMIT_BRANCH &&
$SAST_DEFAULT_ANALYZERS =~ /eslint/
@@ -99,9 +86,11 @@ eslint-sast:
flawfinder-sast:
extends: .sast-analyzer
image:
- name: "$SECURE_ANALYZERS_PREFIX/flawfinder:$SAST_ANALYZER_IMAGE_TAG"
+ name: "$SAST_ANALYZER_IMAGE"
+ variables:
+ SAST_ANALYZER_IMAGE: "$SECURE_ANALYZERS_PREFIX/flawfinder:$SAST_ANALYZER_IMAGE_TAG"
rules:
- - if: $SAST_DISABLED || $SAST_DISABLE_DIND == 'false'
+ - if: $SAST_DISABLED
when: never
- if: $CI_COMMIT_BRANCH &&
$SAST_DEFAULT_ANALYZERS =~ /flawfinder/
@@ -112,9 +101,11 @@ flawfinder-sast:
kubesec-sast:
extends: .sast-analyzer
image:
- name: "$SECURE_ANALYZERS_PREFIX/kubesec:$SAST_ANALYZER_IMAGE_TAG"
+ name: "$SAST_ANALYZER_IMAGE"
+ variables:
+ SAST_ANALYZER_IMAGE: "$SECURE_ANALYZERS_PREFIX/kubesec:$SAST_ANALYZER_IMAGE_TAG"
rules:
- - if: $SAST_DISABLED || $SAST_DISABLE_DIND == 'false'
+ - if: $SAST_DISABLED
when: never
- if: $CI_COMMIT_BRANCH &&
$SAST_DEFAULT_ANALYZERS =~ /kubesec/ &&
@@ -123,9 +114,11 @@ kubesec-sast:
gosec-sast:
extends: .sast-analyzer
image:
- name: "$SECURE_ANALYZERS_PREFIX/gosec:$SAST_ANALYZER_IMAGE_TAG"
+ name: "$SAST_ANALYZER_IMAGE"
+ variables:
+ SAST_ANALYZER_IMAGE: "$SECURE_ANALYZERS_PREFIX/gosec:$SAST_ANALYZER_IMAGE_TAG"
rules:
- - if: $SAST_DISABLED || $SAST_DISABLE_DIND == 'false'
+ - if: $SAST_DISABLED
when: never
- if: $CI_COMMIT_BRANCH &&
$SAST_DEFAULT_ANALYZERS =~ /gosec/
@@ -135,9 +128,11 @@ gosec-sast:
nodejs-scan-sast:
extends: .sast-analyzer
image:
- name: "$SECURE_ANALYZERS_PREFIX/nodejs-scan:$SAST_ANALYZER_IMAGE_TAG"
+ name: "$SAST_ANALYZER_IMAGE"
+ variables:
+ SAST_ANALYZER_IMAGE: "$SECURE_ANALYZERS_PREFIX/nodejs-scan:$SAST_ANALYZER_IMAGE_TAG"
rules:
- - if: $SAST_DISABLED || $SAST_DISABLE_DIND == 'false'
+ - if: $SAST_DISABLED
when: never
- if: $CI_COMMIT_BRANCH &&
$SAST_DEFAULT_ANALYZERS =~ /nodejs-scan/
@@ -147,9 +142,11 @@ nodejs-scan-sast:
phpcs-security-audit-sast:
extends: .sast-analyzer
image:
- name: "$SECURE_ANALYZERS_PREFIX/phpcs-security-audit:$SAST_ANALYZER_IMAGE_TAG"
+ name: "$SAST_ANALYZER_IMAGE"
+ variables:
+ SAST_ANALYZER_IMAGE: "$SECURE_ANALYZERS_PREFIX/phpcs-security-audit:$SAST_ANALYZER_IMAGE_TAG"
rules:
- - if: $SAST_DISABLED || $SAST_DISABLE_DIND == 'false'
+ - if: $SAST_DISABLED
when: never
- if: $CI_COMMIT_BRANCH &&
$SAST_DEFAULT_ANALYZERS =~ /phpcs-security-audit/
@@ -159,31 +156,25 @@ phpcs-security-audit-sast:
pmd-apex-sast:
extends: .sast-analyzer
image:
- name: "$SECURE_ANALYZERS_PREFIX/pmd-apex:$SAST_ANALYZER_IMAGE_TAG"
+ name: "$SAST_ANALYZER_IMAGE"
+ variables:
+ SAST_ANALYZER_IMAGE: "$SECURE_ANALYZERS_PREFIX/pmd-apex:$SAST_ANALYZER_IMAGE_TAG"
rules:
- - if: $SAST_DISABLED || $SAST_DISABLE_DIND == 'false'
+ - if: $SAST_DISABLED
when: never
- if: $CI_COMMIT_BRANCH &&
$SAST_DEFAULT_ANALYZERS =~ /pmd-apex/
exists:
- '**/*.cls'
-secrets-sast:
- extends: .sast-analyzer
- image:
- name: "$SECURE_ANALYZERS_PREFIX/secrets:$SAST_ANALYZER_IMAGE_TAG"
- rules:
- - if: $SAST_DISABLED || $SAST_DISABLE_DIND == 'false'
- when: never
- - if: $CI_COMMIT_BRANCH &&
- $SAST_DEFAULT_ANALYZERS =~ /secrets/
-
security-code-scan-sast:
extends: .sast-analyzer
image:
- name: "$SECURE_ANALYZERS_PREFIX/security-code-scan:$SAST_ANALYZER_IMAGE_TAG"
+ name: "$SAST_ANALYZER_IMAGE"
+ variables:
+ SAST_ANALYZER_IMAGE: "$SECURE_ANALYZERS_PREFIX/security-code-scan:$SAST_ANALYZER_IMAGE_TAG"
rules:
- - if: $SAST_DISABLED || $SAST_DISABLE_DIND == 'false'
+ - if: $SAST_DISABLED
when: never
- if: $CI_COMMIT_BRANCH &&
$SAST_DEFAULT_ANALYZERS =~ /security-code-scan/
@@ -194,9 +185,11 @@ security-code-scan-sast:
sobelow-sast:
extends: .sast-analyzer
image:
- name: "$SECURE_ANALYZERS_PREFIX/sobelow:$SAST_ANALYZER_IMAGE_TAG"
+ name: "$SAST_ANALYZER_IMAGE"
+ variables:
+ SAST_ANALYZER_IMAGE: "$SECURE_ANALYZERS_PREFIX/sobelow:$SAST_ANALYZER_IMAGE_TAG"
rules:
- - if: $SAST_DISABLED || $SAST_DISABLE_DIND == 'false'
+ - if: $SAST_DISABLED
when: never
- if: $CI_COMMIT_BRANCH &&
$SAST_DEFAULT_ANALYZERS =~ /sobelow/
@@ -206,9 +199,11 @@ sobelow-sast:
spotbugs-sast:
extends: .sast-analyzer
image:
- name: "$SECURE_ANALYZERS_PREFIX/spotbugs:$SAST_ANALYZER_IMAGE_TAG"
+ name: "$SAST_ANALYZER_IMAGE"
+ variables:
+ SAST_ANALYZER_IMAGE: "$SECURE_ANALYZERS_PREFIX/spotbugs:$SAST_ANALYZER_IMAGE_TAG"
rules:
- - if: $SAST_DISABLED || $SAST_DISABLE_DIND == 'false'
+ - if: $SAST_DISABLED
when: never
- if: $CI_COMMIT_BRANCH &&
$SAST_DEFAULT_ANALYZERS =~ /spotbugs/
diff --git a/lib/gitlab/ci/templates/Security/Secret-Detection.gitlab-ci.yml b/lib/gitlab/ci/templates/Security/Secret-Detection.gitlab-ci.yml
index b897c7b482f..bde6a0fbebb 100644
--- a/lib/gitlab/ci/templates/Security/Secret-Detection.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Security/Secret-Detection.gitlab-ci.yml
@@ -35,6 +35,7 @@ secret_detection:
- if: $CI_COMMIT_BRANCH && $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH
script:
- git fetch origin $CI_DEFAULT_BRANCH $CI_BUILD_REF_NAME
- - export SECRET_DETECTION_COMMIT_TO=$(git log --left-right --cherry-pick --pretty=format:"%H" refs/remotes/origin/$CI_DEFAULT_BRANCH...refs/remotes/origin/$CI_BUILD_REF_NAME | tail -n 1)
- - export SECRET_DETECTION_COMMIT_FROM=$CI_COMMIT_SHA
+ - git log --left-right --cherry-pick --pretty=format:"%H" refs/remotes/origin/$CI_DEFAULT_BRANCH...refs/remotes/origin/$CI_BUILD_REF_NAME > "$CI_COMMIT_SHA"_commit_list.txt
+ - export SECRET_DETECTION_COMMITS_FILE="$CI_COMMIT_SHA"_commit_list.txt
- /analyzer run
+ - rm "$CI_COMMIT_SHA"_commit_list.txt
diff --git a/lib/gitlab/ci/templates/Verify/Browser-Performance.gitlab-ci.yml b/lib/gitlab/ci/templates/Verify/Browser-Performance.gitlab-ci.yml
index 9dbd9b679a8..e591e3cc1e2 100644
--- a/lib/gitlab/ci/templates/Verify/Browser-Performance.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Verify/Browser-Performance.gitlab-ci.yml
@@ -12,15 +12,15 @@ performance:
variables:
URL: ''
SITESPEED_IMAGE: sitespeedio/sitespeed.io
- SITESPEED_VERSION: 13.3.0
+ SITESPEED_VERSION: 14.1.0
SITESPEED_OPTIONS: ''
services:
- docker:stable-dind
script:
- mkdir gitlab-exporter
- - wget -O ./gitlab-exporter/index.js https://gitlab.com/gitlab-org/gl-performance/raw/master/index.js
+ - wget -O ./gitlab-exporter/index.js https://gitlab.com/gitlab-org/gl-performance/raw/1.1.0/index.js
- mkdir sitespeed-results
- - docker run --shm-size=1g --rm -v "$(pwd)":/sitespeed.io $SITESPEED_IMAGE:$SITESPEED_VERSION --plugins.add ./gitlab-exporter --outputFolder sitespeed-results $URL $SITESPEED_OPTIONS
+ - docker run --shm-size=1g --rm -v "$(pwd)":/sitespeed.io $SITESPEED_IMAGE:$SITESPEED_VERSION --plugins.add ./gitlab-exporter --cpu --outputFolder sitespeed-results $URL $SITESPEED_OPTIONS
- mv sitespeed-results/data/performance.json browser-performance.json
artifacts:
paths:
diff --git a/lib/gitlab/ci/templates/Verify/Load-Performance-Testing.gitlab-ci.yml b/lib/gitlab/ci/templates/Verify/Load-Performance-Testing.gitlab-ci.yml
index f964b3b2caf..cd23af562e5 100644
--- a/lib/gitlab/ci/templates/Verify/Load-Performance-Testing.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Verify/Load-Performance-Testing.gitlab-ci.yml
@@ -14,10 +14,11 @@ load_performance:
K6_VERSION: 0.27.0
K6_TEST_FILE: github.com/loadimpact/k6/samples/http_get.js
K6_OPTIONS: ''
+ K6_DOCKER_OPTIONS: ''
services:
- docker:stable-dind
script:
- - docker run --rm -v "$(pwd)":/k6 -w /k6 $K6_IMAGE:$K6_VERSION run $K6_TEST_FILE --summary-export=load-performance.json $K6_OPTIONS
+ - docker run --rm -v "$(pwd)":/k6 -w /k6 $K6_DOCKER_OPTIONS $K6_IMAGE:$K6_VERSION run $K6_TEST_FILE --summary-export=load-performance.json $K6_OPTIONS
artifacts:
reports:
load_performance: load-performance.json
diff --git a/lib/gitlab/ci/templates/npm.gitlab-ci.yml b/lib/gitlab/ci/templates/npm.gitlab-ci.yml
index 035ba52da84..0a739cf122d 100644
--- a/lib/gitlab/ci/templates/npm.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/npm.gitlab-ci.yml
@@ -55,5 +55,5 @@ publish_package:
npm publish &&
echo "Successfully published version ${NPM_PACKAGE_VERSION} of ${NPM_PACKAGE_NAME} to GitLab's NPM registry: ${CI_PROJECT_URL}/-/packages"
} || {
- echo "No new version of ${NPM_PACKAGE_NAME} published. This is most likely because version ${NPM_PACKAGE_VERSION} already exists in GitLab's NPM registry."
+ echo "No new version of ${NPM_PACKAGE_NAME} published. This is most likely because version ${NPM_PACKAGE_VERSION} already exists in GitLab's NPM registry."; exit 1
}
diff --git a/lib/gitlab/ci/trace.rb b/lib/gitlab/ci/trace.rb
index f76aacc2d19..348e5472cb4 100644
--- a/lib/gitlab/ci/trace.rb
+++ b/lib/gitlab/ci/trace.rb
@@ -79,22 +79,13 @@ module Gitlab
job.trace_chunks.any? || current_path.present? || old_trace.present?
end
- def read
- stream = Gitlab::Ci::Trace::Stream.new do
- if trace_artifact
- trace_artifact.open
- elsif job.trace_chunks.any?
- Gitlab::Ci::Trace::ChunkedIO.new(job)
- elsif current_path
- File.open(current_path, "rb")
- elsif old_trace
- StringIO.new(old_trace)
- end
- end
+ def read(should_retry: true, &block)
+ read_stream(&block)
+ rescue Errno::ENOENT
+ raise unless should_retry
- yield stream
- ensure
- stream&.close
+ job.reset
+ read_stream(&block)
end
def write(mode, &blk)
@@ -141,6 +132,24 @@ module Gitlab
private
+ def read_stream
+ stream = Gitlab::Ci::Trace::Stream.new do
+ if trace_artifact
+ trace_artifact.open
+ elsif job.trace_chunks.any?
+ Gitlab::Ci::Trace::ChunkedIO.new(job)
+ elsif current_path
+ File.open(current_path, "rb")
+ elsif old_trace
+ StringIO.new(old_trace)
+ end
+ end
+
+ yield stream
+ ensure
+ stream&.close
+ end
+
def unsafe_write!(mode, &blk)
stream = Gitlab::Ci::Trace::Stream.new do
if trace_artifact
diff --git a/lib/gitlab/ci/trace/metrics.rb b/lib/gitlab/ci/trace/metrics.rb
new file mode 100644
index 00000000000..82a7d5fb83c
--- /dev/null
+++ b/lib/gitlab/ci/trace/metrics.rb
@@ -0,0 +1,44 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Ci
+ class Trace
+ class Metrics
+ extend Gitlab::Utils::StrongMemoize
+
+ OPERATIONS = [:appended, :streamed, :chunked, :mutated, :overwrite,
+ :accepted, :finalized, :discarded, :conflict].freeze
+
+ def increment_trace_operation(operation: :unknown)
+ unless OPERATIONS.include?(operation)
+ raise ArgumentError, "unknown trace operation: #{operation}"
+ end
+
+ self.class.trace_operations.increment(operation: operation)
+ end
+
+ def increment_trace_bytes(size)
+ self.class.trace_bytes.increment(by: size.to_i)
+ end
+
+ def self.trace_operations
+ strong_memoize(:trace_operations) do
+ name = :gitlab_ci_trace_operations_total
+ comment = 'Total amount of different operations on a build trace'
+
+ Gitlab::Metrics.counter(name, comment)
+ end
+ end
+
+ def self.trace_bytes
+ strong_memoize(:trace_bytes) do
+ name = :gitlab_ci_trace_bytes_total
+ comment = 'Total amount of build trace bytes transferred'
+
+ Gitlab::Metrics.counter(name, comment)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/ci/trace/stream.rb b/lib/gitlab/ci/trace/stream.rb
index 20f5620dd64..618438c8887 100644
--- a/lib/gitlab/ci/trace/stream.rb
+++ b/lib/gitlab/ci/trace/stream.rb
@@ -8,7 +8,7 @@ module Gitlab
BUFFER_SIZE = 4096
LIMIT_SIZE = 500.kilobytes
- attr_reader :stream
+ attr_reader :stream, :metrics
delegate :close, :tell, :seek, :size, :url, :truncate, to: :stream, allow_nil: true
@@ -16,9 +16,10 @@ module Gitlab
alias_method :present?, :valid?
- def initialize
+ def initialize(metrics = Trace::Metrics.new)
@stream = yield
@stream&.binmode
+ @metrics = metrics
end
def valid?
@@ -43,6 +44,9 @@ module Gitlab
def append(data, offset)
data = data.force_encoding(Encoding::BINARY)
+ metrics.increment_trace_operation(operation: :streamed)
+ metrics.increment_trace_bytes(data.bytesize)
+
stream.seek(offset, IO::SEEK_SET)
stream.write(data)
stream.truncate(offset + data.bytesize)
diff --git a/lib/gitlab/ci/warnings.rb b/lib/gitlab/ci/warnings.rb
new file mode 100644
index 00000000000..7138fd21b72
--- /dev/null
+++ b/lib/gitlab/ci/warnings.rb
@@ -0,0 +1,5 @@
+# frozen_string_literal: true
+
+module Gitlab::Ci::Warnings
+ MAX_LIMIT = 25
+end
diff --git a/lib/gitlab/ci/yaml_processor.rb b/lib/gitlab/ci/yaml_processor.rb
index b7046064f44..ee55eb8b22a 100644
--- a/lib/gitlab/ci/yaml_processor.rb
+++ b/lib/gitlab/ci/yaml_processor.rb
@@ -1,183 +1,65 @@
# frozen_string_literal: true
+# This is the CI Linter component that runs the syntax validations
+# while parsing the YAML config into a data structure that is
+# then presented to the caller as result object.
+# After syntax validations (done by Ci::Config), this component also
+# runs logical validation on the built data structure.
module Gitlab
module Ci
class YamlProcessor
- # ValidationError is treated like a result object in the form of an exception.
- # We can return any warnings, raised during the config validation, along with
- # the error object until we support multiple messages to be returned.
- class ValidationError < StandardError
- attr_reader :warnings
-
- def initialize(message, warnings: [])
- @warnings = warnings
- super(message)
- end
- end
-
- include Gitlab::Config::Entry::LegacyValidationHelpers
+ ValidationError = Class.new(StandardError)
- attr_reader :stages, :jobs
+ def self.validation_message(content, opts = {})
+ result = new(content, opts).execute
- class Result
- attr_reader :config, :errors, :warnings
+ result.errors.first
+ end
- def initialize(config: nil, errors: [], warnings: [])
- @config = config
- @errors = errors
- @warnings = warnings
- end
+ def initialize(config_content, opts = {})
+ @config_content = config_content
+ @opts = opts
+ end
- def valid?
- config.present? && errors.empty?
+ def execute
+ if @config_content.blank?
+ return Result.new(errors: ['Please provide content of .gitlab-ci.yml'])
end
- end
- def initialize(config, opts = {})
- @ci_config = Gitlab::Ci::Config.new(config, **opts)
- @config = @ci_config.to_hash
+ @ci_config = Gitlab::Ci::Config.new(@config_content, **@opts)
unless @ci_config.valid?
- error!(@ci_config.errors.first)
+ return Result.new(ci_config: @ci_config, errors: @ci_config.errors, warnings: @ci_config.warnings)
end
- initial_parsing
- rescue Gitlab::Ci::Config::ConfigError => e
- error!(e.message)
- end
-
- def self.new_with_validation_errors(content, opts = {})
- return Result.new(errors: ['Please provide content of .gitlab-ci.yml']) if content.blank?
+ run_logical_validations!
- config = Gitlab::Ci::Config.new(content, **opts)
- return Result.new(errors: config.errors, warnings: config.warnings) unless config.valid?
-
- config = Gitlab::Ci::YamlProcessor.new(content, opts)
- Result.new(config: config, warnings: config.warnings)
-
- rescue ValidationError => e
- Result.new(errors: [e.message], warnings: e.warnings)
+ Result.new(ci_config: @ci_config, warnings: @ci_config&.warnings)
rescue Gitlab::Ci::Config::ConfigError => e
- Result.new(errors: [e.message])
- end
-
- def warnings
- @ci_config&.warnings || []
- end
-
- def builds
- @jobs.map do |name, _|
- build_attributes(name)
- end
- end
-
- def build_attributes(name)
- job = @jobs.fetch(name.to_sym, {})
-
- { stage_idx: @stages.index(job[:stage]),
- stage: job[:stage],
- tag_list: job[:tags],
- name: job[:name].to_s,
- allow_failure: job[:ignore],
- when: job[:when] || 'on_success',
- environment: job[:environment_name],
- coverage_regex: job[:coverage],
- yaml_variables: transform_to_yaml_variables(job[:variables]),
- needs_attributes: job.dig(:needs, :job),
- interruptible: job[:interruptible],
- only: job[:only],
- except: job[:except],
- rules: job[:rules],
- cache: job[:cache],
- resource_group_key: job[:resource_group],
- scheduling_type: job[:scheduling_type],
- secrets: job[:secrets],
- options: {
- image: job[:image],
- services: job[:services],
- artifacts: job[:artifacts],
- dependencies: job[:dependencies],
- cross_dependencies: job.dig(:needs, :cross_dependency),
- job_timeout: job[:timeout],
- before_script: job[:before_script],
- script: job[:script],
- after_script: job[:after_script],
- environment: job[:environment],
- retry: job[:retry],
- parallel: job[:parallel],
- instance: job[:instance],
- start_in: job[:start_in],
- trigger: job[:trigger],
- bridge_needs: job.dig(:needs, :bridge)&.first,
- release: release(job)
- }.compact }.compact
- end
+ Result.new(ci_config: @ci_config, errors: [e.message], warnings: @ci_config&.warnings)
- def release(job)
- job[:release]
- end
-
- def stage_builds_attributes(stage)
- @jobs.values
- .select { |job| job[:stage] == stage }
- .map { |job| build_attributes(job[:name]) }
- end
-
- def stages_attributes
- @stages.uniq.map do |stage|
- seeds = stage_builds_attributes(stage)
-
- { name: stage, index: @stages.index(stage), builds: seeds }
- end
- end
-
- def workflow_attributes
- {
- rules: @config.dig(:workflow, :rules),
- yaml_variables: transform_to_yaml_variables(@variables)
- }
- end
-
- def self.validation_message(content, opts = {})
- return 'Please provide content of .gitlab-ci.yml' if content.blank?
-
- begin
- Gitlab::Ci::YamlProcessor.new(content, opts)
- nil
- rescue ValidationError => e
- e.message
- end
+ rescue ValidationError => e
+ Result.new(ci_config: @ci_config, errors: [e.message], warnings: @ci_config&.warnings)
end
private
- def initial_parsing
- ##
- # Global config
- #
- @variables = @ci_config.variables
+ def run_logical_validations!
@stages = @ci_config.stages
-
- ##
- # Jobs
- #
- @jobs = Ci::Config::Normalizer.new(@ci_config.jobs).normalize_jobs
+ @jobs = @ci_config.normalized_jobs
@jobs.each do |name, job|
- # logical validation for job
- validate_job_stage!(name, job)
- validate_job_dependencies!(name, job)
- validate_job_needs!(name, job)
- validate_dynamic_child_pipeline_dependencies!(name, job)
- validate_job_environment!(name, job)
+ validate_job!(name, job)
end
end
- def transform_to_yaml_variables(variables)
- variables.to_h.map do |key, value|
- { key: key.to_s, value: value, public: true }
- end
+ def validate_job!(name, job)
+ validate_job_stage!(name, job)
+ validate_job_dependencies!(name, job)
+ validate_job_needs!(name, job)
+ validate_dynamic_child_pipeline_dependencies!(name, job)
+ validate_job_environment!(name, job)
end
def validate_job_stage!(name, job)
@@ -188,10 +70,6 @@ module Gitlab
end
end
- def error!(message)
- raise ValidationError.new(message, warnings: warnings)
- end
-
def validate_job_dependencies!(name, job)
return unless job[:dependencies]
@@ -267,6 +145,10 @@ module Gitlab
error!("#{name} job: on_stop job #{on_stop} needs to have action stop defined")
end
end
+
+ def error!(message)
+ raise ValidationError.new(message)
+ end
end
end
end
diff --git a/lib/gitlab/ci/yaml_processor/result.rb b/lib/gitlab/ci/yaml_processor/result.rb
new file mode 100644
index 00000000000..68f61e52df7
--- /dev/null
+++ b/lib/gitlab/ci/yaml_processor/result.rb
@@ -0,0 +1,120 @@
+# frozen_string_literal: true
+
+# A data object that wraps `Ci::Config` and any messages
+# (errors, warnings) generated by the YamlProcessor.
+module Gitlab
+ module Ci
+ class YamlProcessor
+ class Result
+ attr_reader :errors, :warnings
+
+ def initialize(ci_config: nil, errors: [], warnings: [])
+ @ci_config = ci_config
+ @errors = errors || []
+ @warnings = warnings || []
+ end
+
+ def valid?
+ errors.empty?
+ end
+
+ def stages_attributes
+ stages.uniq.map do |stage|
+ seeds = stage_builds_attributes(stage)
+
+ { name: stage, index: stages.index(stage), builds: seeds }
+ end
+ end
+
+ def builds
+ jobs.map do |name, _|
+ build_attributes(name)
+ end
+ end
+
+ def stage_builds_attributes(stage)
+ jobs.values
+ .select { |job| job[:stage] == stage }
+ .map { |job| build_attributes(job[:name]) }
+ end
+
+ def workflow_attributes
+ {
+ rules: hash_config.dig(:workflow, :rules),
+ yaml_variables: transform_to_yaml_variables(variables)
+ }
+ end
+
+ def jobs
+ @jobs ||= @ci_config.normalized_jobs
+ end
+
+ def stages
+ @stages ||= @ci_config.stages
+ end
+
+ def build_attributes(name)
+ job = jobs.fetch(name.to_sym, {})
+
+ { stage_idx: stages.index(job[:stage]),
+ stage: job[:stage],
+ tag_list: job[:tags],
+ name: job[:name].to_s,
+ allow_failure: job[:ignore],
+ when: job[:when] || 'on_success',
+ environment: job[:environment_name],
+ coverage_regex: job[:coverage],
+ yaml_variables: transform_to_yaml_variables(job[:variables]),
+ needs_attributes: job.dig(:needs, :job),
+ interruptible: job[:interruptible],
+ only: job[:only],
+ except: job[:except],
+ rules: job[:rules],
+ cache: job[:cache],
+ resource_group_key: job[:resource_group],
+ scheduling_type: job[:scheduling_type],
+ secrets: job[:secrets],
+ options: {
+ image: job[:image],
+ services: job[:services],
+ artifacts: job[:artifacts],
+ dependencies: job[:dependencies],
+ cross_dependencies: job.dig(:needs, :cross_dependency),
+ job_timeout: job[:timeout],
+ before_script: job[:before_script],
+ script: job[:script],
+ after_script: job[:after_script],
+ environment: job[:environment],
+ retry: job[:retry],
+ parallel: job[:parallel],
+ instance: job[:instance],
+ start_in: job[:start_in],
+ trigger: job[:trigger],
+ bridge_needs: job.dig(:needs, :bridge)&.first,
+ release: release(job)
+ }.compact }.compact
+ end
+
+ private
+
+ def variables
+ @variables ||= @ci_config.variables
+ end
+
+ def hash_config
+ @hash_config ||= @ci_config.to_hash
+ end
+
+ def release(job)
+ job[:release]
+ end
+
+ def transform_to_yaml_variables(variables)
+ variables.to_h.map do |key, value|
+ { key: key.to_s, value: value, public: true }
+ end
+ end
+ end
+ end
+ end
+end