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:
Diffstat (limited to 'spec/lib/gitlab/ci')
-rw-r--r--spec/lib/gitlab/ci/build/image_spec.rb4
-rw-r--r--spec/lib/gitlab/ci/build/policy/changes_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/build/rules_spec.rb12
-rw-r--r--spec/lib/gitlab/ci/config/entry/auto_cancel_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/entry/bridge_spec.rb6
-rw-r--r--spec/lib/gitlab/ci/config/entry/image_spec.rb64
-rw-r--r--spec/lib/gitlab/ci/config/entry/include/rules/rule_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/entry/needs_spec.rb21
-rw-r--r--spec/lib/gitlab/ci/config/entry/rules/rule_spec.rb57
-rw-r--r--spec/lib/gitlab/ci/config/entry/rules_spec.rb8
-rw-r--r--spec/lib/gitlab/ci/config/entry/service_spec.rb47
-rw-r--r--spec/lib/gitlab/ci/config/entry/workflow_spec.rb67
-rw-r--r--spec/lib/gitlab/ci/config/external/context_spec.rb85
-rw-r--r--spec/lib/gitlab/ci/config/external/file/component_spec.rb10
-rw-r--r--spec/lib/gitlab/ci/config/external/file/remote_spec.rb34
-rw-r--r--spec/lib/gitlab/ci/parsers/sbom/cyclonedx_properties_spec.rb225
-rw-r--r--spec/lib/gitlab/ci/parsers/sbom/cyclonedx_spec.rb50
-rw-r--r--spec/lib/gitlab/ci/parsers/sbom/source/trivy_spec.rb25
-rw-r--r--spec/lib/gitlab/ci/parsers/security/common_spec.rb28
-rw-r--r--spec/lib/gitlab/ci/pipeline/chain/command_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/pipeline/chain/evaluate_workflow_rules_spec.rb12
-rw-r--r--spec/lib/gitlab/ci/pipeline/chain/helpers_spec.rb49
-rw-r--r--spec/lib/gitlab/ci/pipeline/chain/populate_metadata_spec.rb72
-rw-r--r--spec/lib/gitlab/ci/pipeline/chain/populate_spec.rb15
-rw-r--r--spec/lib/gitlab/ci/reports/security/report_spec.rb4
-rw-r--r--spec/lib/gitlab/ci/variables/builder/pipeline_spec.rb45
-rw-r--r--spec/lib/gitlab/ci/yaml_processor/test_cases/include_spec.rb80
-rw-r--r--spec/lib/gitlab/ci/yaml_processor/test_cases/interruptible_spec.rb5
-rw-r--r--spec/lib/gitlab/ci/yaml_processor_spec.rb32
29 files changed, 822 insertions, 243 deletions
diff --git a/spec/lib/gitlab/ci/build/image_spec.rb b/spec/lib/gitlab/ci/build/image_spec.rb
index f8c0d69be2e..3854437483d 100644
--- a/spec/lib/gitlab/ci/build/image_spec.rb
+++ b/spec/lib/gitlab/ci/build/image_spec.rb
@@ -29,7 +29,7 @@ RSpec.describe Gitlab::Ci::Build::Image do
context 'when image is defined as hash' do
let(:entrypoint) { '/bin/sh' }
let(:pull_policy) { %w[always if-not-present] }
- let(:executor_opts) { { docker: { platform: 'arm64' } } }
+ let(:executor_opts) { { docker: { platform: 'arm64', user: 'dave' } } }
let(:job) do
create(:ci_build, options: { image: { name: image_name,
@@ -101,7 +101,7 @@ RSpec.describe Gitlab::Ci::Build::Image do
let(:service_entrypoint) { '/bin/sh' }
let(:service_alias) { 'db' }
let(:service_command) { 'sleep 30' }
- let(:executor_opts) { { docker: { platform: 'amd64' } } }
+ let(:executor_opts) { { docker: { platform: 'amd64', user: 'dave' } } }
let(:pull_policy) { %w[always if-not-present] }
let(:job) do
create(:ci_build, options: { services: [{ name: service_image_name, entrypoint: service_entrypoint,
diff --git a/spec/lib/gitlab/ci/build/policy/changes_spec.rb b/spec/lib/gitlab/ci/build/policy/changes_spec.rb
index 00e44650d44..4ee8903dcd3 100644
--- a/spec/lib/gitlab/ci/build/policy/changes_spec.rb
+++ b/spec/lib/gitlab/ci/build/policy/changes_spec.rb
@@ -134,7 +134,7 @@ RSpec.describe Gitlab::Ci::Build::Policy::Changes do
ref: 'feature',
source: source,
sha: '0b4bc9a4',
- before_sha: Gitlab::Git::BLANK_SHA,
+ before_sha: Gitlab::Git::SHA1_BLANK_SHA,
merge_request: merge_request
)
end
diff --git a/spec/lib/gitlab/ci/build/rules_spec.rb b/spec/lib/gitlab/ci/build/rules_spec.rb
index 99577539798..61bd9f41182 100644
--- a/spec/lib/gitlab/ci/build/rules_spec.rb
+++ b/spec/lib/gitlab/ci/build/rules_spec.rb
@@ -254,6 +254,18 @@ RSpec.describe Gitlab::Ci::Build::Rules, feature_category: :pipeline_composition
end
end
+ context 'with auto_cancel' do
+ context 'with matching rule' do
+ let(:rule_list) { [{ if: '$VAR == null', auto_cancel: { on_new_commit: 'interruptible' } }] }
+
+ it do
+ is_expected.to eq(
+ described_class::Result.new(when: 'on_success', auto_cancel: { on_new_commit: 'interruptible' })
+ )
+ end
+ end
+ end
+
context 'with a regexp variable matching rule' do
let(:rule_list) { [{ if: '"abcde" =~ $pattern' }] }
diff --git a/spec/lib/gitlab/ci/config/entry/auto_cancel_spec.rb b/spec/lib/gitlab/ci/config/entry/auto_cancel_spec.rb
index bdd66cc00a1..764908ee040 100644
--- a/spec/lib/gitlab/ci/config/entry/auto_cancel_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/auto_cancel_spec.rb
@@ -25,7 +25,7 @@ RSpec.describe Gitlab::Ci::Config::Entry::AutoCancel, feature_category: :pipelin
it 'returns errors' do
expect(config.errors)
- .to include('auto cancel on new commit must be one of: conservative, interruptible, disabled')
+ .to include('auto cancel on new commit must be one of: conservative, interruptible, none')
end
end
end
diff --git a/spec/lib/gitlab/ci/config/entry/bridge_spec.rb b/spec/lib/gitlab/ci/config/entry/bridge_spec.rb
index 35f2a99ee87..04154b72453 100644
--- a/spec/lib/gitlab/ci/config/entry/bridge_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/bridge_spec.rb
@@ -23,6 +23,12 @@ RSpec.describe Gitlab::Ci::Config::Entry::Bridge, feature_category: :continuous_
end
end
+ describe '.visible?' do
+ it 'always returns true' do
+ expect(described_class.visible?).to be_truthy
+ end
+ end
+
describe '.matching?' do
subject { described_class.matching?(name, config) }
diff --git a/spec/lib/gitlab/ci/config/entry/image_spec.rb b/spec/lib/gitlab/ci/config/entry/image_spec.rb
index 99a6e25b313..0a82010c20c 100644
--- a/spec/lib/gitlab/ci/config/entry/image_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/image_spec.rb
@@ -112,7 +112,7 @@ RSpec.describe Gitlab::Ci::Config::Entry::Image do
end
end
- context "when docker specifies an option" do
+ context "when docker specifies platform" do
let(:config) { { name: 'image:1.0', docker: { platform: 'amd64' } } }
it 'is valid' do
@@ -129,15 +129,73 @@ RSpec.describe Gitlab::Ci::Config::Entry::Image do
)
end
end
+
+ context "when invalid data type is specified for platform option" do
+ let(:config) { { name: 'image:1.0', docker: { platform: 1 } } }
+
+ it 'raises an error' do
+ expect(entry).not_to be_valid
+ expect(entry.errors.first)
+ .to match %r{image executor opts '/docker/platform' must be a valid 'string'}
+ end
+ end
+ end
+
+ context "when docker specifies user" do
+ let(:config) { { name: 'image:1.0', docker: { user: 'dave' } } }
+
+ it 'is valid' do
+ expect(entry).to be_valid
+ end
+
+ describe '#value' do
+ it "returns value" do
+ expect(entry.value).to eq(
+ name: 'image:1.0',
+ executor_opts: {
+ docker: { user: 'dave' }
+ }
+ )
+ end
+ end
+
+ context "when user is a UID" do
+ let(:config) { { name: 'image:1.0', docker: { user: '1001' } } }
+
+ it 'is valid' do
+ expect(entry).to be_valid
+ end
+
+ describe '#value' do
+ it "returns value" do
+ expect(entry.value).to eq(
+ name: 'image:1.0',
+ executor_opts: {
+ docker: { user: '1001' }
+ }
+ )
+ end
+ end
+ end
+
+ context "when invalid data type is specified for user option" do
+ let(:config) { { name: 'image:1.0', docker: { user: 1 } } }
+
+ it 'raises an error' do
+ expect(entry).not_to be_valid
+ expect(entry.errors.first)
+ .to match %r{image executor opts '/docker/user' must be a valid 'string'}
+ end
+ end
end
context "when docker specifies an invalid option" do
- let(:config) { { name: 'image:1.0', docker: { platform: 1 } } }
+ let(:config) { { name: 'image:1.0', docker: { unknown_key: 'foo' } } }
it 'is not valid' do
expect(entry).not_to be_valid
expect(entry.errors.first)
- .to match %r{image executor opts '/docker/platform' must be a valid 'string'}
+ .to match %r{image executor opts '/docker/unknown_key' must be a valid 'schema'}
end
end
end
diff --git a/spec/lib/gitlab/ci/config/entry/include/rules/rule_spec.rb b/spec/lib/gitlab/ci/config/entry/include/rules/rule_spec.rb
index cd8e35ede61..a9f891a7b50 100644
--- a/spec/lib/gitlab/ci/config/entry/include/rules/rule_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/include/rules/rule_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'fast_spec_helper'
+require 'spec_helper'
require_dependency 'active_model'
RSpec.describe Gitlab::Ci::Config::Entry::Include::Rules::Rule, feature_category: :pipeline_composition do
diff --git a/spec/lib/gitlab/ci/config/entry/needs_spec.rb b/spec/lib/gitlab/ci/config/entry/needs_spec.rb
index d1a8a74ac06..61bb3e912ba 100644
--- a/spec/lib/gitlab/ci/config/entry/needs_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/needs_spec.rb
@@ -52,6 +52,27 @@ RSpec.describe ::Gitlab::Ci::Config::Entry::Needs, feature_category: :pipeline_c
end
end
+ context 'when config has disallowed keys' do
+ let(:config) { ['some_value'] }
+
+ before do
+ needs.metadata[:allowed_needs] = %i[cross_dependency]
+ needs.compose!
+ end
+
+ describe '#valid?' do
+ it 'returns invalid' do
+ expect(needs.valid?).to be_falsey
+ end
+ end
+
+ describe '#errors' do
+ it 'returns invalid types error' do
+ expect(needs.errors).to include('needs config uses invalid types: job')
+ end
+ end
+ end
+
context 'when wrong needs type is used' do
let(:config) { [{ job: 'job_name', artifacts: true, some: :key }] }
diff --git a/spec/lib/gitlab/ci/config/entry/rules/rule_spec.rb b/spec/lib/gitlab/ci/config/entry/rules/rule_spec.rb
index 3531d6e9f1a..d5bf532c216 100644
--- a/spec/lib/gitlab/ci/config/entry/rules/rule_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/rules/rule_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
require 'gitlab_chronic_duration'
-RSpec.describe Gitlab::Ci::Config::Entry::Rules::Rule do
+RSpec.describe Gitlab::Ci::Config::Entry::Rules::Rule, feature_category: :pipeline_composition do
let(:factory) do
Gitlab::Config::Entry::Factory.new(described_class)
.metadata(metadata)
@@ -11,7 +11,10 @@ RSpec.describe Gitlab::Ci::Config::Entry::Rules::Rule do
end
let(:metadata) do
- { allowed_when: %w[on_success on_failure always never manual delayed] }
+ {
+ allowed_when: %w[on_success on_failure always never manual delayed],
+ allowed_keys: %i[if changes exists when start_in allow_failure variables needs auto_cancel]
+ }
end
let(:entry) { factory.create! }
@@ -296,18 +299,18 @@ RSpec.describe Gitlab::Ci::Config::Entry::Rules::Rule do
end
end
- context 'with a string passed in metadata but not allowed in the class' do
- let(:metadata) { { allowed_when: %w[explode] } }
+ context 'with an invalid when' do
+ let(:metadata) { { allowed_when: %w[always never], allowed_keys: %i[if when] } }
let(:config) do
- { if: '$THIS == "that"', when: 'explode' }
+ { if: '$THIS == "that"', when: 'on_success' }
end
it { is_expected.to be_a(described_class) }
it { is_expected.not_to be_valid }
it 'returns an error about invalid when:' do
- expect(subject.errors).to include(/when unknown value: explode/)
+ expect(subject.errors).to include(/when unknown value: on_success/)
end
context 'when composed' do
@@ -318,41 +321,30 @@ RSpec.describe Gitlab::Ci::Config::Entry::Rules::Rule do
it { is_expected.not_to be_valid }
it 'returns an error about invalid when:' do
- expect(subject.errors).to include(/when unknown value: explode/)
+ expect(subject.errors).to include(/when unknown value: on_success/)
end
end
end
- context 'with a string allowed in the class but not passed in metadata' do
- let(:metadata) { { allowed_when: %w[always never] } }
-
+ context 'with an invalid variables' do
let(:config) do
- { if: '$THIS == "that"', when: 'on_success' }
+ { if: '$THIS == "that"', variables: 'hello' }
end
- it { is_expected.to be_a(described_class) }
- it { is_expected.not_to be_valid }
-
- it 'returns an error about invalid when:' do
- expect(subject.errors).to include(/when unknown value: on_success/)
+ before do
+ subject.compose!
end
- context 'when composed' do
- before do
- subject.compose!
- end
-
- it { is_expected.not_to be_valid }
+ it { is_expected.not_to be_valid }
- it 'returns an error about invalid when:' do
- expect(subject.errors).to include(/when unknown value: on_success/)
- end
+ it 'returns an error about invalid variables:' do
+ expect(subject.errors).to include(/variables config should be a hash/)
end
end
- context 'with an invalid variables' do
+ context 'with an invalid auto_cancel' do
let(:config) do
- { if: '$THIS == "that"', variables: 'hello' }
+ { if: '$THIS == "that"', auto_cancel: { on_new_commit: 'xyz' } }
end
before do
@@ -361,8 +353,9 @@ RSpec.describe Gitlab::Ci::Config::Entry::Rules::Rule do
it { is_expected.not_to be_valid }
- it 'returns an error about invalid variables:' do
- expect(subject.errors).to include(/variables config should be a hash/)
+ it 'returns an error' do
+ expect(subject.errors).to include(
+ 'auto_cancel on new commit must be one of: conservative, interruptible, none')
end
end
end
@@ -445,6 +438,12 @@ RSpec.describe Gitlab::Ci::Config::Entry::Rules::Rule do
it { is_expected.to eq(config) }
end
+
+ context 'when it has auto_cancel' do
+ let(:config) { { if: '$THIS || $THAT', auto_cancel: { on_new_commit: 'interruptible' } } }
+
+ it { is_expected.to eq(config) }
+ end
end
describe '.default' do
diff --git a/spec/lib/gitlab/ci/config/entry/rules_spec.rb b/spec/lib/gitlab/ci/config/entry/rules_spec.rb
index b0871f2345e..0113b6c1f7f 100644
--- a/spec/lib/gitlab/ci/config/entry/rules_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/rules_spec.rb
@@ -1,16 +1,18 @@
# frozen_string_literal: true
-require 'fast_spec_helper'
+require 'spec_helper'
require_dependency 'active_model'
-RSpec.describe Gitlab::Ci::Config::Entry::Rules do
+RSpec.describe Gitlab::Ci::Config::Entry::Rules, feature_category: :pipeline_composition do
let(:factory) do
Gitlab::Config::Entry::Factory.new(described_class)
.metadata(metadata)
.value(config)
end
- let(:metadata) { { allowed_when: %w[always never] } }
+ let(:metadata) do
+ { allowed_when: %w[always never], allowed_keys: %i[if when] }
+ end
subject(:entry) { factory.create! }
diff --git a/spec/lib/gitlab/ci/config/entry/service_spec.rb b/spec/lib/gitlab/ci/config/entry/service_spec.rb
index 82747e7b521..8ce0f890b46 100644
--- a/spec/lib/gitlab/ci/config/entry/service_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/service_spec.rb
@@ -154,22 +154,45 @@ RSpec.describe Gitlab::Ci::Config::Entry::Service do
end
context 'when configuration has docker options' do
- let(:config) { { name: 'postgresql:9.5', docker: { platform: 'amd64' } } }
+ context "with platform option" do
+ let(:config) { { name: 'postgresql:9.5', docker: { platform: 'amd64' } } }
- describe '#valid?' do
- it 'is valid' do
- expect(entry).to be_valid
+ describe '#valid?' do
+ it 'is valid' do
+ expect(entry).to be_valid
+ end
+ end
+
+ describe '#value' do
+ it "returns value" do
+ expect(entry.value).to eq(
+ name: 'postgresql:9.5',
+ executor_opts: {
+ docker: { platform: 'amd64' }
+ }
+ )
+ end
end
end
- describe '#value' do
- it "returns value" do
- expect(entry.value).to eq(
- name: 'postgresql:9.5',
- executor_opts: {
- docker: { platform: 'amd64' }
- }
- )
+ context "with user option" do
+ let(:config) { { name: 'postgresql:9.5', docker: { user: 'dave' } } }
+
+ describe '#valid?' do
+ it 'is valid' do
+ expect(entry).to be_valid
+ end
+ end
+
+ describe '#value' do
+ it "returns value" do
+ expect(entry.value).to eq(
+ name: 'postgresql:9.5',
+ executor_opts: {
+ docker: { user: 'dave' }
+ }
+ )
+ end
end
end
end
diff --git a/spec/lib/gitlab/ci/config/entry/workflow_spec.rb b/spec/lib/gitlab/ci/config/entry/workflow_spec.rb
index d3ce3ffe641..dbd25010884 100644
--- a/spec/lib/gitlab/ci/config/entry/workflow_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/workflow_spec.rb
@@ -6,6 +6,10 @@ RSpec.describe Gitlab::Ci::Config::Entry::Workflow, feature_category: :pipeline_
subject(:config) { described_class.new(workflow_hash) }
describe 'validations' do
+ before do
+ config.compose!
+ end
+
context 'when work config value is a string' do
let(:workflow_hash) { 'build' }
@@ -27,6 +31,28 @@ RSpec.describe Gitlab::Ci::Config::Entry::Workflow, feature_category: :pipeline_
end
context 'when work config value is a hash' do
+ context 'with an invalid key' do
+ let(:workflow_hash) { { trash: [{ if: '$VAR' }] } }
+
+ describe '#valid?' do
+ it 'is invalid' do
+ expect(config).not_to be_valid
+ end
+
+ it 'attaches an error specifying the unknown key' do
+ expect(config.errors).to include('workflow config contains unknown keys: trash')
+ end
+ end
+
+ describe '#value' do
+ it 'returns the invalid configuration' do
+ expect(config.value).to eq(workflow_hash)
+ end
+ end
+ end
+ end
+
+ context 'when config has rules' do
let(:workflow_hash) { { rules: [{ if: '$VAR' }] } }
describe '#valid?' do
@@ -45,8 +71,8 @@ RSpec.describe Gitlab::Ci::Config::Entry::Workflow, feature_category: :pipeline_
end
end
- context 'with an invalid key' do
- let(:workflow_hash) { { trash: [{ if: '$VAR' }] } }
+ context 'when rules has an invalid key' do
+ let(:workflow_hash) { { rules: [{ if: '$VAR', trash: 'something' }] } }
describe '#valid?' do
it 'is invalid' do
@@ -54,7 +80,7 @@ RSpec.describe Gitlab::Ci::Config::Entry::Workflow, feature_category: :pipeline_
end
it 'attaches an error specifying the unknown key' do
- expect(config.errors).to include('workflow config contains unknown keys: trash')
+ expect(config.errors).to include('rules:rule config contains unknown keys: trash')
end
end
@@ -64,6 +90,41 @@ RSpec.describe Gitlab::Ci::Config::Entry::Workflow, feature_category: :pipeline_
end
end
end
+
+ context 'when rules has auto_cancel' do
+ let(:workflow_hash) { { rules: [{ if: '$VAR', auto_cancel: { on_new_commit: 'interruptible' } }] } }
+
+ describe '#valid?' do
+ it 'is valid' do
+ expect(config).to be_valid
+ end
+
+ it 'attaches no errors' do
+ expect(config.errors).to be_empty
+ end
+ end
+
+ describe '#value' do
+ it 'returns the config' do
+ expect(config.value).to eq(workflow_hash)
+ end
+ end
+
+ context 'when auto_cancel has an invalid value' do
+ let(:workflow_hash) { { rules: [{ if: '$VAR', auto_cancel: { on_new_commit: 'xyz' } }] } }
+
+ describe '#valid?' do
+ it 'is invalid' do
+ expect(config).not_to be_valid
+ end
+
+ it 'returns error' do
+ expect(config.errors).to include(
+ 'rules:rule:auto_cancel on new commit must be one of: conservative, interruptible, none')
+ end
+ end
+ end
+ end
end
end
diff --git a/spec/lib/gitlab/ci/config/external/context_spec.rb b/spec/lib/gitlab/ci/config/external/context_spec.rb
index 9ac72ebbac8..3409fc53d19 100644
--- a/spec/lib/gitlab/ci/config/external/context_spec.rb
+++ b/spec/lib/gitlab/ci/config/external/context_spec.rb
@@ -159,10 +159,14 @@ RSpec.describe Gitlab::Ci::Config::External::Context, feature_category: :pipelin
shared_examples 'a mutated context' do
let(:mutated) { subject.mutate(new_attributes) }
+ let(:lazy_response) { double('lazy_response') }
before do
+ allow(lazy_response).to receive(:execute).and_return(lazy_response)
+
subject.expandset << :a_file
subject.set_deadline(15.seconds)
+ subject.execute_remote_parallel_request(lazy_response)
end
it { expect(mutated).not_to eq(subject) }
@@ -170,8 +174,9 @@ RSpec.describe Gitlab::Ci::Config::External::Context, feature_category: :pipelin
it { expect(mutated).to have_attributes(new_attributes) }
it { expect(mutated.pipeline).to eq(subject.pipeline) }
it { expect(mutated.expandset).to eq(subject.expandset) }
- it { expect(mutated.execution_deadline).to eq(mutated.execution_deadline) }
- it { expect(mutated.logger).to eq(mutated.logger) }
+ it { expect(mutated.execution_deadline).to eq(subject.execution_deadline) }
+ it { expect(mutated.logger).to eq(subject.logger) }
+ it { expect(mutated.parallel_requests).to eq(subject.parallel_requests) }
end
context 'with attributes' do
@@ -212,4 +217,80 @@ RSpec.describe Gitlab::Ci::Config::External::Context, feature_category: :pipelin
end
end
end
+
+ describe '#execute_remote_parallel_request' do
+ let(:lazy_response1) { double('lazy_response', wait: true, complete?: complete1) }
+ let(:lazy_response2) { double('lazy_response') }
+
+ let(:complete1) { false }
+
+ before do
+ allow(lazy_response1).to receive(:execute).and_return(lazy_response1)
+ allow(lazy_response2).to receive(:execute).and_return(lazy_response2)
+ end
+
+ context 'when the queue is empty' do
+ before do
+ stub_const("Gitlab::Ci::Config::External::Context::MAX_PARALLEL_REMOTE_REQUESTS", 2)
+ end
+
+ it 'adds the new lazy response to the queue' do
+ expect { subject.execute_remote_parallel_request(lazy_response1) }
+ .to change { subject.parallel_requests }
+ .from([])
+ .to([lazy_response1])
+ end
+ end
+
+ context 'when there is a lazy response in the queue' do
+ before do
+ subject.execute_remote_parallel_request(lazy_response1)
+ end
+
+ context 'when there is a free slot in the queue' do
+ before do
+ stub_const("Gitlab::Ci::Config::External::Context::MAX_PARALLEL_REMOTE_REQUESTS", 2)
+ end
+
+ it 'adds the new lazy response to the queue' do
+ expect { subject.execute_remote_parallel_request(lazy_response2) }
+ .to change { subject.parallel_requests }
+ .from([lazy_response1])
+ .to([lazy_response1, lazy_response2])
+ end
+ end
+
+ context 'when the queue is full' do
+ before do
+ stub_const("Gitlab::Ci::Config::External::Context::MAX_PARALLEL_REMOTE_REQUESTS", 1)
+ end
+
+ context 'when the first lazy response in the queue is complete' do
+ let(:complete1) { true }
+
+ it 'removes the completed lazy response and adds the new one to the queue' do
+ expect(lazy_response1).not_to receive(:wait)
+
+ expect { subject.execute_remote_parallel_request(lazy_response2) }
+ .to change { subject.parallel_requests }
+ .from([lazy_response1])
+ .to([lazy_response2])
+ end
+ end
+
+ context 'when the first lazy response in the queue is not complete' do
+ let(:complete1) { false }
+
+ it 'waits for the first lazy response to complete and then adds the new one to the queue' do
+ expect(lazy_response1).to receive(:wait)
+
+ expect { subject.execute_remote_parallel_request(lazy_response2) }
+ .to change { subject.parallel_requests }
+ .from([lazy_response1])
+ .to([lazy_response1, lazy_response2])
+ end
+ end
+ end
+ end
+ end
end
diff --git a/spec/lib/gitlab/ci/config/external/file/component_spec.rb b/spec/lib/gitlab/ci/config/external/file/component_spec.rb
index 88e272ac3fd..7907837db6a 100644
--- a/spec/lib/gitlab/ci/config/external/file/component_spec.rb
+++ b/spec/lib/gitlab/ci/config/external/file/component_spec.rb
@@ -146,6 +146,16 @@ RSpec.describe Gitlab::Ci::Config::External::File::Component, feature_category:
external_resource.content
end
+
+ context 'when user is missing in a context' do
+ let_it_be(:user) { nil }
+
+ it 'does not track the event' do
+ expect(::Gitlab::UsageDataCounters::HLLRedisCounter).not_to receive(:track_event)
+
+ external_resource.content
+ end
+ end
end
context 'when component is invalid' do
diff --git a/spec/lib/gitlab/ci/config/external/file/remote_spec.rb b/spec/lib/gitlab/ci/config/external/file/remote_spec.rb
index 7293e640112..adca9e750d0 100644
--- a/spec/lib/gitlab/ci/config/external/file/remote_spec.rb
+++ b/spec/lib/gitlab/ci/config/external/file/remote_spec.rb
@@ -157,6 +157,40 @@ RSpec.describe Gitlab::Ci::Config::External::File::Remote, feature_category: :pi
it_behaves_like "#content"
end
+ describe '#preload_content' do
+ context 'when the parallel request queue is full' do
+ let(:location1) { 'https://gitlab.com/gitlab-org/gitlab-foss/blob/1234/.secret_file1.yml' }
+ let(:location2) { 'https://gitlab.com/gitlab-org/gitlab-foss/blob/1234/.secret_file2.yml' }
+
+ before do
+ # Makes the parallel queue full easily
+ stub_const("Gitlab::Ci::Config::External::Context::MAX_PARALLEL_REMOTE_REQUESTS", 1)
+
+ # Adding a failing promise to the queue
+ promise = Concurrent::Promise.new do
+ sleep 1.1
+ raise Timeout::Error
+ end
+
+ context.execute_remote_parallel_request(
+ Gitlab::HTTP_V2::LazyResponse.new(promise, location1, {}, nil)
+ )
+
+ stub_full_request(location2).to_return(body: remote_file_content)
+ end
+
+ it 'waits for the queue' do
+ file2 = described_class.new({ remote: location2 }, context)
+
+ start_at = Time.current
+ file2.preload_content
+ end_at = Time.current
+
+ expect(end_at - start_at).to be > 1
+ end
+ end
+ end
+
describe "#error_message" do
subject(:error_message) do
Gitlab::Ci::Config::External::Mapper::Verifier.new(context).process([remote_file])
diff --git a/spec/lib/gitlab/ci/parsers/sbom/cyclonedx_properties_spec.rb b/spec/lib/gitlab/ci/parsers/sbom/cyclonedx_properties_spec.rb
index 2c57106b07c..9718d16756c 100644
--- a/spec/lib/gitlab/ci/parsers/sbom/cyclonedx_properties_spec.rb
+++ b/spec/lib/gitlab/ci/parsers/sbom/cyclonedx_properties_spec.rb
@@ -3,118 +3,173 @@
require 'fast_spec_helper'
RSpec.describe Gitlab::Ci::Parsers::Sbom::CyclonedxProperties, feature_category: :dependency_management do
- subject(:parse_source_from_properties) { described_class.parse_source(properties) }
+ shared_examples 'handling invalid properties' do
+ context 'when properties are nil' do
+ let(:properties) { nil }
- context 'when properties are nil' do
- let(:properties) { nil }
+ it { is_expected.to be_nil }
+ end
+
+ context 'when report does not have valid properties' do
+ let(:properties) { ['name' => 'foo', 'value' => 'bar'] }
- it { is_expected.to be_nil }
+ it { is_expected.to be_nil }
+ end
end
- context 'when report does not have gitlab properties' do
- let(:properties) { ['name' => 'foo', 'value' => 'bar'] }
+ describe '#parse_source' do
+ subject(:parse_source_from_properties) { described_class.parse_source(properties) }
- it { is_expected.to be_nil }
- end
+ it_behaves_like 'handling invalid properties'
- context 'when schema_version is missing' do
- let(:properties) do
- [
- { 'name' => 'gitlab:dependency_scanning:dependency_file', 'value' => 'package-lock.json' },
- { 'name' => 'gitlab:dependency_scanning:package_manager_name', 'value' => 'npm' },
- { 'name' => 'gitlab:dependency_scanning:language', 'value' => 'JavaScript' }
- ]
- end
+ context 'when schema_version is missing' do
+ let(:properties) do
+ [
+ { 'name' => 'gitlab:dependency_scanning:dependency_file', 'value' => 'package-lock.json' },
+ { 'name' => 'gitlab:dependency_scanning:package_manager_name', 'value' => 'npm' },
+ { 'name' => 'gitlab:dependency_scanning:language', 'value' => 'JavaScript' }
+ ]
+ end
- it { is_expected.to be_nil }
- end
+ it { is_expected.to be_nil }
+ end
- context 'when schema version is unsupported' do
- let(:properties) do
- [
- { 'name' => 'gitlab:meta:schema_version', 'value' => '2' },
- { 'name' => 'gitlab:dependency_scanning:dependency_file', 'value' => 'package-lock.json' },
- { 'name' => 'gitlab:dependency_scanning:package_manager_name', 'value' => 'npm' },
- { 'name' => 'gitlab:dependency_scanning:language', 'value' => 'JavaScript' }
- ]
+ context 'when schema version is unsupported' do
+ let(:properties) do
+ [
+ { 'name' => 'gitlab:meta:schema_version', 'value' => '2' },
+ { 'name' => 'gitlab:dependency_scanning:dependency_file', 'value' => 'package-lock.json' },
+ { 'name' => 'gitlab:dependency_scanning:package_manager_name', 'value' => 'npm' },
+ { 'name' => 'gitlab:dependency_scanning:language', 'value' => 'JavaScript' }
+ ]
+ end
+
+ it { is_expected.to be_nil }
end
- it { is_expected.to be_nil }
- end
+ context 'when no dependency_scanning or container_scanning properties are present' do
+ let(:properties) do
+ [
+ { 'name' => 'gitlab:meta:schema_version', 'value' => '1' },
+ { 'name' => 'gitlab::aquasecurity:trivy:FilePath', 'value' => '1' }
+ ]
+ end
- context 'when no dependency_scanning or container_scanning properties are present' do
- let(:properties) do
- [
- { 'name' => 'gitlab:meta:schema_version', 'value' => '1' }
- ]
+ it 'does not call source parsers' do
+ expect(Gitlab::Ci::Parsers::Sbom::Source::DependencyScanning).not_to receive(:source)
+ expect(Gitlab::Ci::Parsers::Sbom::Source::ContainerScanning).not_to receive(:source)
+
+ parse_source_from_properties
+ end
end
- it 'does not call source parsers' do
- expect(Gitlab::Ci::Parsers::Sbom::Source::DependencyScanning).not_to receive(:source)
- expect(Gitlab::Ci::Parsers::Sbom::Source::ContainerScanning).not_to receive(:source)
+ context 'when dependency_scanning properties are present' do
+ let(:properties) do
+ [
+ { 'name' => 'gitlab:meta:schema_version', 'value' => '1' },
+ { 'name' => 'gitlab:dependency_scanning:category', 'value' => 'development' },
+ { 'name' => 'gitlab:dependency_scanning:input_file:path', 'value' => 'package-lock.json' },
+ { 'name' => 'gitlab:dependency_scanning:source_file:path', 'value' => 'package.json' },
+ { 'name' => 'gitlab:dependency_scanning:package_manager:name', 'value' => 'npm' },
+ { 'name' => 'gitlab:dependency_scanning:language:name', 'value' => 'JavaScript' },
+ { 'name' => 'gitlab:dependency_scanning:unsupported_property', 'value' => 'Should be ignored' }
+ ]
+ end
+
+ let(:expected_input) do
+ {
+ 'category' => 'development',
+ 'input_file' => { 'path' => 'package-lock.json' },
+ 'source_file' => { 'path' => 'package.json' },
+ 'package_manager' => { 'name' => 'npm' },
+ 'language' => { 'name' => 'JavaScript' }
+ }
+ end
- parse_source_from_properties
- end
- end
+ it 'passes only supported properties to the dependency scanning parser' do
+ expect(Gitlab::Ci::Parsers::Sbom::Source::DependencyScanning).to receive(:source).with(expected_input)
- context 'when dependency_scanning properties are present' do
- let(:properties) do
- [
- { 'name' => 'gitlab:meta:schema_version', 'value' => '1' },
- { 'name' => 'gitlab:dependency_scanning:category', 'value' => 'development' },
- { 'name' => 'gitlab:dependency_scanning:input_file:path', 'value' => 'package-lock.json' },
- { 'name' => 'gitlab:dependency_scanning:source_file:path', 'value' => 'package.json' },
- { 'name' => 'gitlab:dependency_scanning:package_manager:name', 'value' => 'npm' },
- { 'name' => 'gitlab:dependency_scanning:language:name', 'value' => 'JavaScript' },
- { 'name' => 'gitlab:dependency_scanning:unsupported_property', 'value' => 'Should be ignored' }
- ]
+ parse_source_from_properties
+ end
end
- let(:expected_input) do
- {
- 'category' => 'development',
- 'input_file' => { 'path' => 'package-lock.json' },
- 'source_file' => { 'path' => 'package.json' },
- 'package_manager' => { 'name' => 'npm' },
- 'language' => { 'name' => 'JavaScript' }
- }
- end
+ context 'when container_scanning properties are present' do
+ let(:properties) do
+ [
+ { 'name' => 'gitlab:meta:schema_version', 'value' => '1' },
+ { 'name' => 'gitlab:container_scanning:image:name', 'value' => 'photon' },
+ { 'name' => 'gitlab:container_scanning:image:tag', 'value' => '5.0-20231007' },
+ { 'name' => 'gitlab:container_scanning:operating_system:name', 'value' => 'Photon OS' },
+ { 'name' => 'gitlab:container_scanning:operating_system:version', 'value' => '5.0' }
+ ]
+ end
+
+ let(:expected_input) do
+ {
+ 'image' => {
+ 'name' => 'photon',
+ 'tag' => '5.0-20231007'
+ },
+ 'operating_system' => {
+ 'name' => 'Photon OS',
+ 'version' => '5.0'
+ }
+ }
+ end
- it 'passes only supported properties to the dependency scanning parser' do
- expect(Gitlab::Ci::Parsers::Sbom::Source::DependencyScanning).to receive(:source).with(expected_input)
+ it 'passes only supported properties to the container scanning parser' do
+ expect(Gitlab::Ci::Parsers::Sbom::Source::ContainerScanning).to receive(:source).with(expected_input)
- parse_source_from_properties
+ parse_source_from_properties
+ end
end
end
- context 'when container_scanning properties are present' do
- let(:properties) do
- [
- { 'name' => 'gitlab:meta:schema_version', 'value' => '1' },
- { 'name' => 'gitlab:container_scanning:image:name', 'value' => 'photon' },
- { 'name' => 'gitlab:container_scanning:image:tag', 'value' => '5.0-20231007' },
- { 'name' => 'gitlab:container_scanning:operating_system:name', 'value' => 'Photon OS' },
- { 'name' => 'gitlab:container_scanning:operating_system:version', 'value' => '5.0' }
- ]
+ describe '#parse_trivy_source' do
+ subject(:parse_trivy_source_from_properties) { described_class.parse_trivy_source(properties) }
+
+ it_behaves_like 'handling invalid properties'
+
+ context 'when no trivy properties are present' do
+ let(:properties) do
+ [
+ { 'name' => 'gitlab:meta:schema_version', 'value' => '1' },
+ { 'name' => 'gitlab::aquasecurity:trivy:FilePath', 'value' => '1' }
+ ]
+ end
+
+ it 'does not call source parsers' do
+ expect(Gitlab::Ci::Parsers::Sbom::Source::Trivy).not_to receive(:source)
+
+ parse_trivy_source_from_properties
+ end
end
- let(:expected_input) do
- {
- 'image' => {
- 'name' => 'photon',
- 'tag' => '5.0-20231007'
- },
- 'operating_system' => {
- 'name' => 'Photon OS',
- 'version' => '5.0'
+ context 'when trivy properties are present' do
+ let(:properties) do
+ [
+ { 'name' => 'aquasecurity:trivy:PkgID', 'value' => 'sha256:47ce8fad8..' },
+ { 'name' => 'aquasecurity:trivy:LayerDigest',
+ 'value' => 'registry.test.com/atiwari71/container-scanning-test/main@sha256:e14a4bcf..' },
+ { 'name' => 'aquasecurity:trivy:LayerDiffID', 'value' => 'sha256:94dd7d531fa..' },
+ { 'name' => 'aquasecurity:trivy:SrcEpoch', 'value' => 'sha256:5d20c808c..' }
+ ]
+ end
+
+ let(:expected_input) do
+ {
+ 'PkgID' => 'sha256:47ce8fad8..',
+ 'LayerDigest' => 'registry.test.com/atiwari71/container-scanning-test/main@sha256:e14a4bcf..',
+ 'LayerDiffID' => 'sha256:94dd7d531fa..',
+ 'SrcEpoch' => 'sha256:5d20c808c..'
}
- }
- end
+ end
- it 'passes only supported properties to the container scanning parser' do
- expect(Gitlab::Ci::Parsers::Sbom::Source::ContainerScanning).to receive(:source).with(expected_input)
+ it 'passes only supported properties to the container scanning parser' do
+ expect(Gitlab::Ci::Parsers::Sbom::Source::Trivy).to receive(:source).with(expected_input)
- parse_source_from_properties
+ parse_trivy_source_from_properties
+ end
end
end
end
diff --git a/spec/lib/gitlab/ci/parsers/sbom/cyclonedx_spec.rb b/spec/lib/gitlab/ci/parsers/sbom/cyclonedx_spec.rb
index 9c8402faf77..6a6fe59bce1 100644
--- a/spec/lib/gitlab/ci/parsers/sbom/cyclonedx_spec.rb
+++ b/spec/lib/gitlab/ci/parsers/sbom/cyclonedx_spec.rb
@@ -125,6 +125,56 @@ RSpec.describe Gitlab::Ci::Parsers::Sbom::Cyclonedx, feature_category: :dependen
parse!
end
+ context 'when component is trivy type' do
+ let(:parsed_properties) do
+ {
+ 'PkgID' => 'adduser@3.134',
+ 'PkgType' => 'debian'
+ }
+ end
+
+ let(:components) do
+ [
+ {
+ # Trivy component
+ "bom-ref" => "0eda252d-d8a4-4250-b816-b6314f029063",
+ "type" => "library",
+ "name" => "analyzer",
+ "purl" => "pkg:gem/activesupport@5.1.4",
+ "properties" => [
+ {
+ "name" => "aquasecurity:trivy:PkgID",
+ "value" => "apt@2.6.1"
+ },
+ {
+ "name" => "aquasecurity:trivy:PkgType",
+ "value" => "debian"
+ }
+ ]
+ }
+ ]
+ end
+
+ before do
+ allow(properties_parser).to receive(:parse_trivy_source).and_return(parsed_properties)
+ stub_const('Gitlab::Ci::Parsers::Sbom::CyclonedxProperties', properties_parser)
+ end
+
+ it 'adds each component, ignoring unused attributes' do
+ expect(report).to receive(:add_component)
+ .with(
+ an_object_having_attributes(
+ component_type: "library",
+ properties: parsed_properties,
+ purl: an_object_having_attributes(
+ type: "gem"
+ )
+ )
+ )
+ parse!
+ end
+ end
+
context 'when a component has an invalid purl' do
before do
components.push(
diff --git a/spec/lib/gitlab/ci/parsers/sbom/source/trivy_spec.rb b/spec/lib/gitlab/ci/parsers/sbom/source/trivy_spec.rb
new file mode 100644
index 00000000000..460ca4f28a1
--- /dev/null
+++ b/spec/lib/gitlab/ci/parsers/sbom/source/trivy_spec.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+require 'fast_spec_helper'
+
+RSpec.describe Gitlab::Ci::Parsers::Sbom::Source::Trivy, feature_category: :dependency_management do
+ subject { described_class.source(property_data) }
+
+ context 'when all property data is present' do
+ let(:property_data) do
+ {
+ 'PkgID' => 'sha256:47ce8fad8..',
+ 'LayerDigest' => 'registry.test.com/atiwari71/container-scanning-test/main@sha256:e14a4bcf..',
+ 'LayerDiffID' => 'sha256:94dd7d531fa..',
+ 'SrcEpoch' => 'sha256:5d20c808c..'
+ }
+ end
+
+ it 'returns expected source data' do
+ is_expected.to have_attributes(
+ source_type: :trivy,
+ data: property_data
+ )
+ end
+ end
+end
diff --git a/spec/lib/gitlab/ci/parsers/security/common_spec.rb b/spec/lib/gitlab/ci/parsers/security/common_spec.rb
index 431a6d94c48..6aa526c1829 100644
--- a/spec/lib/gitlab/ci/parsers/security/common_spec.rb
+++ b/spec/lib/gitlab/ci/parsers/security/common_spec.rb
@@ -185,7 +185,7 @@ RSpec.describe Gitlab::Ci::Parsers::Security::Common, feature_category: :vulnera
context 'when name is provided' do
it 'sets name from the report as a name' do
- finding = report.findings.find { |x| x.compare_key == 'CVE-1030' }
+ finding = report.findings.second
expected_name = Gitlab::Json.parse(finding.raw_metadata)['name']
expect(finding.name).to eq(expected_name)
@@ -197,7 +197,8 @@ RSpec.describe Gitlab::Ci::Parsers::Security::Common, feature_category: :vulnera
let(:location) { nil }
it 'returns only identifier name' do
- finding = report.findings.find { |x| x.compare_key == 'CVE-2017-11429' }
+ finding = report.findings.third
+
expect(finding.name).to eq("CVE-2017-11429")
end
end
@@ -205,21 +206,24 @@ RSpec.describe Gitlab::Ci::Parsers::Security::Common, feature_category: :vulnera
context 'when location exists' do
context 'when CVE identifier exists' do
it 'combines identifier with location to create name' do
- finding = report.findings.find { |x| x.compare_key == 'CVE-2017-11429' }
+ finding = report.findings.third
+
expect(finding.name).to eq("CVE-2017-11429 in yarn.lock")
end
end
context 'when CWE identifier exists' do
it 'combines identifier with location to create name' do
- finding = report.findings.find { |x| x.compare_key == 'CWE-2017-11429' }
+ finding = report.findings.fourth
+
expect(finding.name).to eq("CWE-2017-11429 in yarn.lock")
end
end
context 'when neither CVE nor CWE identifier exist' do
it 'combines identifier with location to create name' do
- finding = report.findings.find { |x| x.compare_key == 'OTHER-2017-11429' }
+ finding = report.findings.fifth
+
expect(finding.name).to eq("other-2017-11429 in yarn.lock")
end
end
@@ -476,6 +480,20 @@ RSpec.describe Gitlab::Ci::Parsers::Security::Common, feature_category: :vulnera
end
end
end
+
+ describe 'handling the unicode null characters' do
+ let(:artifact) { build(:ci_job_artifact, :common_security_report_with_unicode_null_character) }
+
+ it 'escapes the unicode null characters while parsing the report' do
+ finding = report.findings.first
+
+ expect(finding.solution).to eq('Upgrade to latest version.\u0000')
+ end
+
+ it 'adds warning to report' do
+ expect(report.warnings).to include({ type: 'Parsing', message: 'Report artifact contained unicode null characters which are escaped during the ingestion.' })
+ end
+ end
end
end
end
diff --git a/spec/lib/gitlab/ci/pipeline/chain/command_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/command_spec.rb
index 68158503628..37535b80cd4 100644
--- a/spec/lib/gitlab/ci/pipeline/chain/command_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/chain/command_spec.rb
@@ -200,7 +200,7 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Command do
let(:command) { described_class.new(project: project) }
it 'uses BLANK_SHA' do
- is_expected.to eq(Gitlab::Git::BLANK_SHA)
+ is_expected.to eq(Gitlab::Git::SHA1_BLANK_SHA)
end
end
end
diff --git a/spec/lib/gitlab/ci/pipeline/chain/evaluate_workflow_rules_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/evaluate_workflow_rules_spec.rb
index 44ccb1eeae1..bf146791659 100644
--- a/spec/lib/gitlab/ci/pipeline/chain/evaluate_workflow_rules_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/chain/evaluate_workflow_rules_spec.rb
@@ -12,13 +12,10 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::EvaluateWorkflowRules do
end
let(:step) { described_class.new(pipeline, command) }
- let(:ff_always_set_pipeline_failure_reason) { true }
describe '#perform!' do
context 'when pipeline has been skipped by workflow configuration' do
before do
- stub_feature_flags(always_set_pipeline_failure_reason: ff_always_set_pipeline_failure_reason)
-
allow(step).to receive(:workflow_rules_result)
.and_return(
double(pass?: false, variables: {})
@@ -47,15 +44,6 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::EvaluateWorkflowRules do
expect(pipeline).to be_failed
expect(pipeline).to be_filtered_by_workflow_rules
end
-
- context 'when always_set_pipeline_failure_reason is disabled' do
- let(:ff_always_set_pipeline_failure_reason) { false }
-
- it 'does not set the failure reason', :aggregate_failures do
- expect(pipeline).not_to be_failed
- expect(pipeline.failure_reason).to be_blank
- end
- end
end
context 'when pipeline has not been skipped by workflow configuration' do
diff --git a/spec/lib/gitlab/ci/pipeline/chain/helpers_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/helpers_spec.rb
index 84c2fb6525e..5956137a725 100644
--- a/spec/lib/gitlab/ci/pipeline/chain/helpers_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/chain/helpers_spec.rb
@@ -52,22 +52,6 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Helpers, feature_category: :continuo
expect(pipeline.status).to eq 'failed'
expect(pipeline.failure_reason).to eq drop_reason.to_s
end
-
- context 'when feature flag always_set_pipeline_failure_reason is false' do
- before do
- stub_feature_flags(always_set_pipeline_failure_reason: false)
- end
-
- specify do
- subject.error(message, config_error: config_error, drop_reason: drop_reason)
-
- if command.save_incompleted
- expect(pipeline.failure_reason).to eq drop_reason.to_s
- else
- expect(pipeline.failure_reason).not_to be_present
- end
- end
- end
end
context 'when the error includes malicious HTML' do
@@ -93,6 +77,37 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Helpers, feature_category: :continuo
end
end
+ context 'when drop_reason is nil' do
+ let(:command) { double(project: nil) }
+
+ shared_examples "error function with no drop reason" do
+ it 'drops with out failure reason' do
+ expect(command).to receive(:increment_pipeline_failure_reason_counter)
+
+ call_error
+
+ expect(pipeline.failure_reason).to be_nil
+ expect(pipeline.yaml_errors).to be_nil
+ expect(pipeline.errors[:base]).to include(message)
+ expect(pipeline).to be_failed
+ expect(pipeline).not_to be_persisted
+ end
+ end
+
+ context 'when no drop_reason argument is passed' do
+ let(:call_error) { subject.error(message) }
+
+ it_behaves_like "error function with no drop reason"
+ end
+
+ context 'when drop_reason argument is passed as nil' do
+ let(:drop_reason) { nil }
+ let(:call_error) { subject.error(message, drop_reason: drop_reason) }
+
+ it_behaves_like "error function with no drop reason"
+ end
+ end
+
context 'when config error is false' do
context 'does not set the yaml error or override the drop reason' do
let(:drop_reason) { :size_limit_exceeded }
@@ -107,7 +122,7 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Helpers, feature_category: :continuo
expect(pipeline).to be_persisted
end
- context ' when the drop reason is not persistable' do
+ context 'when the drop reason is not persistable' do
let(:drop_reason) { :filtered_by_rules }
let(:command) { double(project: nil) }
diff --git a/spec/lib/gitlab/ci/pipeline/chain/populate_metadata_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/populate_metadata_spec.rb
index 732748d8c8b..787a458f0ff 100644
--- a/spec/lib/gitlab/ci/pipeline/chain/populate_metadata_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/chain/populate_metadata_spec.rb
@@ -240,6 +240,78 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::PopulateMetadata, feature_category:
expect(pipeline.pipeline_metadata).not_to be_persisted
end
end
+
+ context 'with workflow:rules:auto_cancel' do
+ context 'with auto_cancel:on_new_commit not set and rules:workflow:auto_cancel:on_new_commit set' do
+ let(:config) do
+ {
+ variables: { MY_VAR: my_var_value },
+ workflow: {
+ auto_cancel: { on_job_failure: 'all' },
+ rules: [{ if: '$MY_VAR == "something"', auto_cancel: { on_new_commit: 'interruptible' } }]
+ },
+ rspec: { script: 'rspec' }
+ }
+ end
+
+ context 'when the rule is matched' do
+ let(:my_var_value) { 'something' }
+
+ it 'builds pipeline_metadata' do
+ run_chain
+
+ expect(pipeline.pipeline_metadata.auto_cancel_on_new_commit).to eq('interruptible')
+ expect(pipeline.pipeline_metadata.auto_cancel_on_job_failure).to eq('all')
+ end
+ end
+
+ context 'when the rule is not matched' do
+ let(:my_var_value) { 'something else' }
+
+ it 'builds pipeline_metadata' do
+ run_chain
+
+ expect(pipeline.pipeline_metadata.auto_cancel_on_new_commit).to eq('conservative')
+ expect(pipeline.pipeline_metadata.auto_cancel_on_job_failure).to eq('all')
+ end
+ end
+ end
+
+ context 'with auto_cancel:on_new_commit set and rules:workflow:auto_cancel:on_new_commit set' do
+ let(:config) do
+ {
+ variables: { MY_VAR: my_var_value },
+ workflow: {
+ auto_cancel: { on_new_commit: 'interruptible' },
+ rules: [{ if: '$MY_VAR == "something"', auto_cancel: { on_new_commit: 'none' } }]
+ },
+ rspec: { script: 'rspec' }
+ }
+ end
+
+ context 'when the rule is matched' do
+ let(:my_var_value) { 'something' }
+
+ it 'builds pipeline_metadata' do
+ run_chain
+
+ expect(pipeline.pipeline_metadata.auto_cancel_on_new_commit).to eq('none')
+ expect(pipeline.pipeline_metadata.auto_cancel_on_job_failure).to eq('none')
+ end
+ end
+
+ context 'when the rule is not matched' do
+ let(:my_var_value) { 'something else' }
+
+ it 'builds pipeline_metadata' do
+ run_chain
+
+ expect(pipeline.pipeline_metadata.auto_cancel_on_new_commit).to eq('interruptible')
+ expect(pipeline.pipeline_metadata.auto_cancel_on_job_failure).to eq('none')
+ end
+ end
+ end
+ end
end
context 'with both pipeline name and auto_cancel' do
diff --git a/spec/lib/gitlab/ci/pipeline/chain/populate_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/populate_spec.rb
index 476b1be35a9..22ff367c746 100644
--- a/spec/lib/gitlab/ci/pipeline/chain/populate_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/chain/populate_spec.rb
@@ -34,15 +34,12 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Populate, feature_category: :continu
{ rspec: { script: 'rspec' } }
end
- let(:ff_always_set_pipeline_failure_reason) { true }
-
def run_chain
dependencies.map(&:perform!)
step.perform!
end
before do
- stub_feature_flags(always_set_pipeline_failure_reason: ff_always_set_pipeline_failure_reason)
stub_ci_pipeline_yaml_file(YAML.dump(config))
end
@@ -113,18 +110,6 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Populate, feature_category: :continu
expect(pipeline).to be_failed
expect(pipeline).to be_filtered_by_rules
end
-
- context 'when ff always_set_pipeline_failure_reason is disabled' do
- let(:ff_always_set_pipeline_failure_reason) { false }
-
- it 'sets the failure reason without persisting the pipeline', :aggregate_failures do
- run_chain
-
- expect(pipeline).not_to be_persisted
- expect(pipeline).not_to be_failed
- expect(pipeline).not_to be_filtered_by_rules
- end
- end
end
describe 'pipeline protect' do
diff --git a/spec/lib/gitlab/ci/reports/security/report_spec.rb b/spec/lib/gitlab/ci/reports/security/report_spec.rb
index d7f967f1c55..dabee0f32de 100644
--- a/spec/lib/gitlab/ci/reports/security/report_spec.rb
+++ b/spec/lib/gitlab/ci/reports/security/report_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::Ci::Reports::Security::Report do
+RSpec.describe Gitlab::Ci::Reports::Security::Report, feature_category: :vulnerability_management do
let_it_be(:pipeline) { create(:ci_pipeline) }
let(:created_at) { 2.weeks.ago }
@@ -89,7 +89,7 @@ RSpec.describe Gitlab::Ci::Reports::Security::Report do
let(:other_report) do
create(
:ci_reports_security_report,
- findings: [create(:ci_reports_security_finding, compare_key: 'other_finding')],
+ findings: [create(:ci_reports_security_finding)],
scanners: [create(:ci_reports_security_scanner, external_id: 'other_scanner', name: 'Other Scanner')],
identifiers: [create(:ci_reports_security_identifier, external_id: 'other_id', name: 'other_scanner')]
)
diff --git a/spec/lib/gitlab/ci/variables/builder/pipeline_spec.rb b/spec/lib/gitlab/ci/variables/builder/pipeline_spec.rb
index f8d67a6f0b4..18ad723b75c 100644
--- a/spec/lib/gitlab/ci/variables/builder/pipeline_spec.rb
+++ b/spec/lib/gitlab/ci/variables/builder/pipeline_spec.rb
@@ -152,51 +152,6 @@ RSpec.describe Gitlab::Ci::Variables::Builder::Pipeline, feature_category: :secr
end
end
- context 'when truncate_ci_merge_request_description feature flag is disabled' do
- before do
- stub_feature_flags(truncate_ci_merge_request_description: false)
- end
-
- context 'when merge request description hits the limit' do
- let(:merge_request_description) { 'a' * (MergeRequest::CI_MERGE_REQUEST_DESCRIPTION_MAX_LENGTH + 1) }
-
- it 'does not truncate the exposed description' do
- expect(subject.to_hash)
- .to include(
- 'CI_MERGE_REQUEST_DESCRIPTION' => merge_request.description
- )
- expect(subject.to_hash)
- .not_to have_key('CI_MERGE_REQUEST_DESCRIPTION_IS_TRUNCATED')
- end
- end
-
- context 'when merge request description fits the length limit' do
- let(:merge_request_description) { 'a' * (MergeRequest::CI_MERGE_REQUEST_DESCRIPTION_MAX_LENGTH - 1) }
-
- it 'does not truncate the exposed description' do
- expect(subject.to_hash)
- .to include(
- 'CI_MERGE_REQUEST_DESCRIPTION' => merge_request.description
- )
- expect(subject.to_hash)
- .not_to have_key('CI_MERGE_REQUEST_DESCRIPTION_IS_TRUNCATED')
- end
- end
-
- context 'when merge request description does not exist' do
- let(:merge_request_description) { nil }
-
- it 'does not truncate the exposed description' do
- expect(subject.to_hash)
- .to include(
- 'CI_MERGE_REQUEST_DESCRIPTION' => merge_request.description
- )
- expect(subject.to_hash)
- .not_to have_key('CI_MERGE_REQUEST_DESCRIPTION_IS_TRUNCATED')
- end
- end
- end
-
it 'exposes diff variables' do
expect(subject.to_hash)
.to include(
diff --git a/spec/lib/gitlab/ci/yaml_processor/test_cases/include_spec.rb b/spec/lib/gitlab/ci/yaml_processor/test_cases/include_spec.rb
new file mode 100644
index 00000000000..d8f8a58edf3
--- /dev/null
+++ b/spec/lib/gitlab/ci/yaml_processor/test_cases/include_spec.rb
@@ -0,0 +1,80 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+module Gitlab
+ module Ci
+ RSpec.describe YamlProcessor, feature_category: :pipeline_composition do
+ include StubRequests
+
+ subject(:processor) do
+ described_class.new(config, project: project, user: project.first_owner, logger: logger)
+ end
+
+ let_it_be(:project) { create(:project, :repository) }
+
+ let(:logger) { Gitlab::Ci::Pipeline::Logger.new(project: project) }
+ let(:result) { processor.execute }
+ let(:builds) { result.builds }
+
+ context 'with include:remote' do
+ let(:config) do
+ <<~YAML
+ include:
+ - remote: http://my.domain.com/config1.yml
+ - remote: http://my.domain.com/config2.yml
+ YAML
+ end
+
+ before do
+ stub_full_request('http://my.domain.com/config1.yml')
+ .to_return(body: 'build1: { script: echo Hello World }')
+
+ stub_full_request('http://my.domain.com/config2.yml')
+ .to_return(body: 'build2: { script: echo Hello World }')
+ end
+
+ it 'returns builds from included files' do
+ expect(builds.pluck(:name)).to eq %w[build1 build2]
+ end
+
+ it 'stores instrumentation logs' do
+ result
+
+ expect(logger.observations_hash['config_mapper_process_duration_s']['count']).to eq(1)
+ end
+
+ # Remove with the FF ci_parallel_remote_includes
+ it 'does not store log with config_file_fetch_remote_content' do
+ result
+
+ expect(logger.observations_hash).not_to have_key('config_file_fetch_remote_content_duration_s')
+ end
+
+ context 'when the FF ci_parallel_remote_includes is disabled' do
+ before do
+ stub_feature_flags(ci_parallel_remote_includes: false)
+ end
+
+ it 'stores log with config_file_fetch_remote_content' do
+ result
+
+ expect(logger.observations_hash['config_file_fetch_remote_content_duration_s']['count']).to eq(2)
+ end
+
+ context 'when the FF is specifically enabled for the project' do
+ before do
+ stub_feature_flags(ci_parallel_remote_includes: [project])
+ end
+
+ it 'does not store log with config_file_fetch_remote_content' do
+ result
+
+ expect(logger.observations_hash).not_to have_key('config_file_fetch_remote_content_duration_s')
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/ci/yaml_processor/test_cases/interruptible_spec.rb b/spec/lib/gitlab/ci/yaml_processor/test_cases/interruptible_spec.rb
index 03ff7077969..297872f4cf3 100644
--- a/spec/lib/gitlab/ci/yaml_processor/test_cases/interruptible_spec.rb
+++ b/spec/lib/gitlab/ci/yaml_processor/test_cases/interruptible_spec.rb
@@ -5,9 +5,10 @@ require 'spec_helper'
module Gitlab
module Ci
RSpec.describe YamlProcessor, feature_category: :pipeline_composition do
- subject(:processor) { described_class.new(config, user: nil).execute }
+ subject(:processor) { described_class.new(config, user: nil) }
- let(:builds) { processor.builds }
+ let(:result) { processor.execute }
+ let(:builds) { result.builds }
context 'with interruptible' do
let(:default_config) { nil }
diff --git a/spec/lib/gitlab/ci/yaml_processor_spec.rb b/spec/lib/gitlab/ci/yaml_processor_spec.rb
index 844a6849c8f..4f759109b26 100644
--- a/spec/lib/gitlab/ci/yaml_processor_spec.rb
+++ b/spec/lib/gitlab/ci/yaml_processor_spec.rb
@@ -516,6 +516,32 @@ module Gitlab
})
end
end
+
+ context 'with rules and auto_cancel' do
+ let(:config) do
+ <<-YML
+ workflow:
+ rules:
+ - if: $VAR == "value"
+ auto_cancel:
+ on_new_commit: none
+ on_job_failure: none
+
+ hello:
+ script: echo world
+ YML
+ end
+
+ it 'parses workflow_rules' do
+ expect(subject.workflow_rules).to contain_exactly({
+ if: '$VAR == "value"',
+ auto_cancel: {
+ on_new_commit: 'none',
+ on_job_failure: 'none'
+ }
+ })
+ end
+ end
end
describe '#warnings' do
@@ -1295,10 +1321,12 @@ module Gitlab
name: ruby:2.7
docker:
platform: linux/amd64
+ user: dave
services:
- name: postgres:11.9
docker:
platform: linux/amd64
+ user: john
YAML
end
@@ -1313,9 +1341,9 @@ module Gitlab
options: {
script: ["exit 0"],
image: { name: "ruby:2.7",
- executor_opts: { docker: { platform: 'linux/amd64' } } },
+ executor_opts: { docker: { platform: 'linux/amd64', user: 'dave' } } },
services: [{ name: "postgres:11.9",
- executor_opts: { docker: { platform: 'linux/amd64' } } }]
+ executor_opts: { docker: { platform: 'linux/amd64', user: 'john' } } }]
},
allow_failure: false,
when: "on_success",