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:
authorGrzegorz Bizon <grzegorz@gitlab.com>2019-02-27 13:29:08 +0300
committerGrzegorz Bizon <grzegorz@gitlab.com>2019-02-27 13:29:08 +0300
commit1b10b77babf008daf337ff194f10508935a8c8a2 (patch)
treedc4bd3ccbdabed07f9b5a41a4ffd43d74eb99580
parent8909c06a0b2d84a40b5f58a1ab0d955e9bb299bc (diff)
parent3a2f42925fab6ff398bd85447fbb3bd5ff42cae9 (diff)
Merge branch 'include-ci-yaml' into 'master'
fix: validate 'include' keywords in gitlab-ci.yml configuration files Closes #55863 See merge request gitlab-org/gitlab-ce!24098
-rw-r--r--changelogs/unreleased/include-ci-yaml.yml5
-rw-r--r--lib/gitlab/ci/config/entry/global.rb3
-rw-r--r--lib/gitlab/ci/config/entry/include.rb23
-rw-r--r--lib/gitlab/ci/config/entry/includes.rb32
-rw-r--r--spec/lib/gitlab/ci/config/entry/global_spec.rb6
-rw-r--r--spec/lib/gitlab/ci/yaml_processor_spec.rb79
6 files changed, 145 insertions, 3 deletions
diff --git a/changelogs/unreleased/include-ci-yaml.yml b/changelogs/unreleased/include-ci-yaml.yml
new file mode 100644
index 00000000000..5909950ef0b
--- /dev/null
+++ b/changelogs/unreleased/include-ci-yaml.yml
@@ -0,0 +1,5 @@
+---
+title: Validate 'include' keywords in gitlab-ci.yml configuration files.
+merge_request: 24098
+author: Paul Bonaud
+type: fixed
diff --git a/lib/gitlab/ci/config/entry/global.rb b/lib/gitlab/ci/config/entry/global.rb
index 09ecb5fdb99..2b5a59c078e 100644
--- a/lib/gitlab/ci/config/entry/global.rb
+++ b/lib/gitlab/ci/config/entry/global.rb
@@ -17,6 +17,9 @@ module Gitlab
entry :image, Entry::Image,
description: 'Docker image that will be used to execute jobs.'
+ entry :include, Entry::Includes,
+ description: 'List of external YAML files to include.'
+
entry :services, Entry::Services,
description: 'Docker images that will be linked to the container.'
diff --git a/lib/gitlab/ci/config/entry/include.rb b/lib/gitlab/ci/config/entry/include.rb
new file mode 100644
index 00000000000..f2f3dd84eda
--- /dev/null
+++ b/lib/gitlab/ci/config/entry/include.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Ci
+ class Config
+ module Entry
+ ##
+ # Entry that represents a single include.
+ #
+ class Include < ::Gitlab::Config::Entry::Node
+ include ::Gitlab::Config::Entry::Validatable
+
+ ALLOWED_KEYS = %i[local file remote template].freeze
+
+ validations do
+ validates :config, hash_or_string: true
+ validates :config, allowed_keys: ALLOWED_KEYS
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/ci/config/entry/includes.rb b/lib/gitlab/ci/config/entry/includes.rb
new file mode 100644
index 00000000000..82b2b1ccf4b
--- /dev/null
+++ b/lib/gitlab/ci/config/entry/includes.rb
@@ -0,0 +1,32 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Ci
+ class Config
+ module Entry
+ ##
+ # Entry that represents a list of include.
+ #
+ class Includes < ::Gitlab::Config::Entry::Node
+ include ::Gitlab::Config::Entry::Validatable
+
+ validations do
+ validates :config, type: Array
+ end
+
+ def self.aspects
+ super.append -> do
+ @config = Array.wrap(@config)
+
+ @config.each_with_index do |config, i|
+ @entries[i] = ::Gitlab::Config::Entry::Factory.new(Entry::Include)
+ .value(config || {})
+ .create!
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/ci/config/entry/global_spec.rb b/spec/lib/gitlab/ci/config/entry/global_spec.rb
index 7651f594a4c..e23efff18d5 100644
--- a/spec/lib/gitlab/ci/config/entry/global_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/global_spec.rb
@@ -13,7 +13,7 @@ describe Gitlab::Ci::Config::Entry::Global do
expect(described_class.nodes.keys)
.to match_array(%i[before_script image services
after_script variables stages
- types cache])
+ types cache include])
end
end
end
@@ -42,7 +42,7 @@ describe Gitlab::Ci::Config::Entry::Global do
end
it 'creates node object for each entry' do
- expect(global.descendants.count).to eq 8
+ expect(global.descendants.count).to eq 9
end
it 'creates node object using valid class' do
@@ -189,7 +189,7 @@ describe Gitlab::Ci::Config::Entry::Global do
describe '#nodes' do
it 'instantizes all nodes' do
- expect(global.descendants.count).to eq 8
+ expect(global.descendants.count).to eq 9
end
it 'contains unspecified nodes' do
diff --git a/spec/lib/gitlab/ci/yaml_processor_spec.rb b/spec/lib/gitlab/ci/yaml_processor_spec.rb
index 91139d421f5..29638ef47c5 100644
--- a/spec/lib/gitlab/ci/yaml_processor_spec.rb
+++ b/spec/lib/gitlab/ci/yaml_processor_spec.rb
@@ -602,6 +602,85 @@ module Gitlab
end
end
+ describe "Include" do
+ let(:opts) { {} }
+
+ let(:config) do
+ {
+ include: include_content,
+ rspec: { script: "test" }
+ }
+ end
+
+ subject { Gitlab::Ci::YamlProcessor.new(YAML.dump(config), opts) }
+
+ context "when validating a ci config file with no project context" do
+ context "when an array is provided" do
+ let(:include_content) { ["/local.gitlab-ci.yml"] }
+
+ it "does not return any error" do
+ expect { subject }.not_to raise_error
+ end
+ end
+
+ context "when an array of wrong keyed object is provided" do
+ let(:include_content) { [{ yolo: "/local.gitlab-ci.yml" }] }
+
+ it "returns a validation error" do
+ expect { subject }.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError)
+ end
+ end
+
+ context "when an array of mixed typed objects is provided" do
+ let(:include_content) do
+ [
+ 'https://gitlab.com/awesome-project/raw/master/.before-script-template.yml',
+ '/templates/.after-script-template.yml',
+ { template: 'Auto-DevOps.gitlab-ci.yml' }
+ ]
+ end
+
+ it "does not return any error" do
+ expect { subject }.not_to raise_error
+ end
+ end
+
+ context "when the include type is incorrect" do
+ let(:include_content) { { name: "/local.gitlab-ci.yml" } }
+
+ it "returns an invalid configuration error" do
+ expect { subject }.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError)
+ end
+ end
+ end
+
+ context "when validating a ci config file within a project" do
+ let(:include_content) { "/local.gitlab-ci.yml" }
+ let(:project) { create(:project, :repository) }
+ let(:opts) { { project: project, sha: project.commit.sha } }
+
+ context "when the included internal file is present" do
+ before do
+ expect(project.repository).to receive(:blob_data_at)
+ .and_return(YAML.dump({ job1: { script: 'hello' } }))
+ end
+
+ it "does not return an error" do
+ expect { subject }.not_to raise_error
+ end
+ end
+
+ context "when the included internal file is not present" do
+ it "returns an error with missing file details" do
+ expect { subject }.to raise_error(
+ Gitlab::Ci::YamlProcessor::ValidationError,
+ "Local file `#{include_content}` does not exist!"
+ )
+ end
+ end
+ end
+ end
+
describe "When" do
%w(on_success on_failure always).each do |when_state|
it "returns #{when_state} when defined" do