Commit 27c053e3 authored by Marius Bobin's avatar Marius Bobin

Merge branch 'extract-validate-from-ci-external-file-base-initialize' into 'master'

Move CI external file validation from the initialize method

See merge request gitlab-org/gitlab!83949
parents 75f60a12 a817f2e2
...@@ -16,8 +16,6 @@ module Gitlab ...@@ -16,8 +16,6 @@ module Gitlab
@params = params @params = params
@context = context @context = context
@errors = [] @errors = []
validate!
end end
def matching? def matching?
...@@ -48,6 +46,15 @@ module Gitlab ...@@ -48,6 +46,15 @@ module Gitlab
expanded_content_hash expanded_content_hash
end end
def validate!
context.logger.instrument(:config_file_validation) do
validate_execution_time!
validate_location!
validate_content! if errors.none?
validate_hash! if errors.none?
end
end
protected protected
def expanded_content_hash def expanded_content_hash
...@@ -66,13 +73,6 @@ module Gitlab ...@@ -66,13 +73,6 @@ module Gitlab
nil nil
end end
def validate!
validate_execution_time!
validate_location!
validate_content! if errors.none?
validate_hash! if errors.none?
end
def validate_execution_time! def validate_execution_time!
context.check_execution_time! context.check_execution_time!
end end
......
...@@ -50,6 +50,7 @@ module Gitlab ...@@ -50,6 +50,7 @@ module Gitlab
.map(&method(:expand_variables)) .map(&method(:expand_variables))
.each(&method(:verify_duplicates!)) .each(&method(:verify_duplicates!))
.map(&method(:select_first_matching)) .map(&method(:select_first_matching))
.each(&method(:verify!))
end end
def normalize_location(location) def normalize_location(location)
...@@ -147,6 +148,10 @@ module Gitlab ...@@ -147,6 +148,10 @@ module Gitlab
matching.first matching.first
end end
def verify!(location_object)
location_object.validate!
end
def expand_variables(data) def expand_variables(data)
logger.instrument(:config_mapper_variables) do logger.instrument(:config_mapper_variables) do
expand_variables_without_instrumentation(data) expand_variables_without_instrumentation(data)
......
...@@ -29,14 +29,15 @@ RSpec.describe Gitlab::Ci::Config::External::File::Artifact do ...@@ -29,14 +29,15 @@ RSpec.describe Gitlab::Ci::Config::External::File::Artifact do
end end
describe '#valid?' do describe '#valid?' do
shared_examples 'is invalid' do subject(:valid?) do
it 'is not valid' do external_file.validate!
expect(external_file).not_to be_valid external_file.valid?
end end
shared_examples 'is invalid' do
it 'sets the expected error' do it 'sets the expected error' do
expect(external_file.errors) expect(valid?).to be_falsy
.to contain_exactly(expected_error) expect(external_file.errors).to contain_exactly(expected_error)
end end
end end
...@@ -142,7 +143,7 @@ RSpec.describe Gitlab::Ci::Config::External::File::Artifact do ...@@ -142,7 +143,7 @@ RSpec.describe Gitlab::Ci::Config::External::File::Artifact do
context 'when file is not empty' do context 'when file is not empty' do
it 'is valid' do it 'is valid' do
expect(external_file).to be_valid expect(valid?).to be_truthy
expect(external_file.content).to be_present expect(external_file.content).to be_present
end end
...@@ -154,6 +155,7 @@ RSpec.describe Gitlab::Ci::Config::External::File::Artifact do ...@@ -154,6 +155,7 @@ RSpec.describe Gitlab::Ci::Config::External::File::Artifact do
user: anything user: anything
} }
expect(context).to receive(:mutate).with(expected_attrs).and_call_original expect(context).to receive(:mutate).with(expected_attrs).and_call_original
external_file.validate!
external_file.content external_file.content
end end
end end
......
...@@ -16,7 +16,7 @@ RSpec.describe Gitlab::Ci::Config::External::File::Base do ...@@ -16,7 +16,7 @@ RSpec.describe Gitlab::Ci::Config::External::File::Base do
end end
end end
subject { test_class.new(location, context) } subject(:file) { test_class.new(location, context) }
before do before do
allow_any_instance_of(test_class) allow_any_instance_of(test_class)
...@@ -31,7 +31,7 @@ RSpec.describe Gitlab::Ci::Config::External::File::Base do ...@@ -31,7 +31,7 @@ RSpec.describe Gitlab::Ci::Config::External::File::Base do
let(:location) { 'some-location' } let(:location) { 'some-location' }
it 'returns true' do it 'returns true' do
expect(subject).to be_matching expect(file).to be_matching
end end
end end
...@@ -39,40 +39,45 @@ RSpec.describe Gitlab::Ci::Config::External::File::Base do ...@@ -39,40 +39,45 @@ RSpec.describe Gitlab::Ci::Config::External::File::Base do
let(:location) { nil } let(:location) { nil }
it 'returns false' do it 'returns false' do
expect(subject).not_to be_matching expect(file).not_to be_matching
end end
end end
end end
describe '#valid?' do describe '#valid?' do
subject(:valid?) do
file.validate!
file.valid?
end
context 'when location is not a string' do context 'when location is not a string' do
let(:location) { %w(some/file.txt other/file.txt) } let(:location) { %w(some/file.txt other/file.txt) }
it { is_expected.not_to be_valid } it { is_expected.to be_falsy }
end end
context 'when location is not a YAML file' do context 'when location is not a YAML file' do
let(:location) { 'some/file.txt' } let(:location) { 'some/file.txt' }
it { is_expected.not_to be_valid } it { is_expected.to be_falsy }
end end
context 'when location has not a valid naming scheme' do context 'when location has not a valid naming scheme' do
let(:location) { 'some/file/.yml' } let(:location) { 'some/file/.yml' }
it { is_expected.not_to be_valid } it { is_expected.to be_falsy }
end end
context 'when location is a valid .yml extension' do context 'when location is a valid .yml extension' do
let(:location) { 'some/file/config.yml' } let(:location) { 'some/file/config.yml' }
it { is_expected.to be_valid } it { is_expected.to be_truthy }
end end
context 'when location is a valid .yaml extension' do context 'when location is a valid .yaml extension' do
let(:location) { 'some/file/config.yaml' } let(:location) { 'some/file/config.yaml' }
it { is_expected.to be_valid } it { is_expected.to be_truthy }
end end
context 'when there are YAML syntax errors' do context 'when there are YAML syntax errors' do
...@@ -84,8 +89,8 @@ RSpec.describe Gitlab::Ci::Config::External::File::Base do ...@@ -84,8 +89,8 @@ RSpec.describe Gitlab::Ci::Config::External::File::Base do
end end
it 'is not a valid file' do it 'is not a valid file' do
expect(subject).not_to be_valid expect(valid?).to be_falsy
expect(subject.error_message).to match /does not have valid YAML syntax/ expect(file.error_message).to match /does not have valid YAML syntax/
end end
end end
end end
...@@ -101,7 +106,7 @@ RSpec.describe Gitlab::Ci::Config::External::File::Base do ...@@ -101,7 +106,7 @@ RSpec.describe Gitlab::Ci::Config::External::File::Base do
end end
it 'does expand hash to include the template' do it 'does expand hash to include the template' do
expect(subject.to_hash).to include(:before_script) expect(file.to_hash).to include(:before_script)
end end
end end
end end
......
...@@ -54,6 +54,11 @@ RSpec.describe Gitlab::Ci::Config::External::File::Local do ...@@ -54,6 +54,11 @@ RSpec.describe Gitlab::Ci::Config::External::File::Local do
end end
describe '#valid?' do describe '#valid?' do
subject(:valid?) do
local_file.validate!
local_file.valid?
end
context 'when is a valid local path' do context 'when is a valid local path' do
let(:location) { '/lib/gitlab/ci/templates/existent-file.yml' } let(:location) { '/lib/gitlab/ci/templates/existent-file.yml' }
...@@ -61,25 +66,19 @@ RSpec.describe Gitlab::Ci::Config::External::File::Local do ...@@ -61,25 +66,19 @@ RSpec.describe Gitlab::Ci::Config::External::File::Local do
allow_any_instance_of(described_class).to receive(:fetch_local_content).and_return("image: 'ruby2:2'") allow_any_instance_of(described_class).to receive(:fetch_local_content).and_return("image: 'ruby2:2'")
end end
it 'returns true' do it { is_expected.to be_truthy }
expect(local_file.valid?).to be_truthy
end
end end
context 'when is not a valid local path' do context 'when is not a valid local path' do
let(:location) { '/lib/gitlab/ci/templates/non-existent-file.yml' } let(:location) { '/lib/gitlab/ci/templates/non-existent-file.yml' }
it 'returns false' do it { is_expected.to be_falsy }
expect(local_file.valid?).to be_falsy
end
end end
context 'when is not a yaml file' do context 'when is not a yaml file' do
let(:location) { '/config/application.rb' } let(:location) { '/config/application.rb' }
it 'returns false' do it { is_expected.to be_falsy }
expect(local_file.valid?).to be_falsy
end
end end
context 'when the given sha is not valid' do context 'when the given sha is not valid' do
...@@ -87,7 +86,7 @@ RSpec.describe Gitlab::Ci::Config::External::File::Local do ...@@ -87,7 +86,7 @@ RSpec.describe Gitlab::Ci::Config::External::File::Local do
let(:sha) { ':' } let(:sha) { ':' }
it 'returns false and adds an error message stating that included file does not exist' do it 'returns false and adds an error message stating that included file does not exist' do
expect(local_file).not_to be_valid expect(valid?).to be_falsy
expect(local_file.errors).to include("Sha #{sha} is not valid!") expect(local_file.errors).to include("Sha #{sha} is not valid!")
end end
end end
...@@ -128,6 +127,10 @@ RSpec.describe Gitlab::Ci::Config::External::File::Local do ...@@ -128,6 +127,10 @@ RSpec.describe Gitlab::Ci::Config::External::File::Local do
describe '#error_message' do describe '#error_message' do
let(:location) { '/lib/gitlab/ci/templates/non-existent-file.yml' } let(:location) { '/lib/gitlab/ci/templates/non-existent-file.yml' }
before do
local_file.validate!
end
it 'returns an error message' do it 'returns an error message' do
expect(local_file.error_message).to eq("Local file `#{location}` does not exist!") expect(local_file.error_message).to eq("Local file `#{location}` does not exist!")
end end
...@@ -162,6 +165,8 @@ RSpec.describe Gitlab::Ci::Config::External::File::Local do ...@@ -162,6 +165,8 @@ RSpec.describe Gitlab::Ci::Config::External::File::Local do
allow(project.repository).to receive(:blob_data_at).with(sha, another_location) allow(project.repository).to receive(:blob_data_at).with(sha, another_location)
.and_return(another_content) .and_return(another_content)
local_file.validate!
end end
it 'does expand hash to include the template' do it 'does expand hash to include the template' do
......
...@@ -65,6 +65,11 @@ RSpec.describe Gitlab::Ci::Config::External::File::Project do ...@@ -65,6 +65,11 @@ RSpec.describe Gitlab::Ci::Config::External::File::Project do
end end
describe '#valid?' do describe '#valid?' do
subject(:valid?) do
project_file.validate!
project_file.valid?
end
context 'when a valid path is used' do context 'when a valid path is used' do
let(:params) do let(:params) do
{ project: project.full_path, file: '/file.yml' } { project: project.full_path, file: '/file.yml' }
...@@ -76,15 +81,13 @@ RSpec.describe Gitlab::Ci::Config::External::File::Project do ...@@ -76,15 +81,13 @@ RSpec.describe Gitlab::Ci::Config::External::File::Project do
stub_project_blob(root_ref_sha, '/file.yml') { 'image: ruby:2.7' } stub_project_blob(root_ref_sha, '/file.yml') { 'image: ruby:2.7' }
end end
it 'returns true' do it { is_expected.to be_truthy }
expect(project_file).to be_valid
end
context 'when user does not have permission to access file' do context 'when user does not have permission to access file' do
let(:context_user) { create(:user) } let(:context_user) { create(:user) }
it 'returns false' do it 'returns false' do
expect(project_file).not_to be_valid expect(valid?).to be_falsy
expect(project_file.error_message).to include("Project `#{project.full_path}` not found or access denied!") expect(project_file.error_message).to include("Project `#{project.full_path}` not found or access denied!")
end end
end end
...@@ -101,9 +104,7 @@ RSpec.describe Gitlab::Ci::Config::External::File::Project do ...@@ -101,9 +104,7 @@ RSpec.describe Gitlab::Ci::Config::External::File::Project do
stub_project_blob(ref_sha, '/file.yml') { 'image: ruby:2.7' } stub_project_blob(ref_sha, '/file.yml') { 'image: ruby:2.7' }
end end
it 'returns true' do it { is_expected.to be_truthy }
expect(project_file).to be_valid
end
end end
context 'when an empty file is used' do context 'when an empty file is used' do
...@@ -118,7 +119,7 @@ RSpec.describe Gitlab::Ci::Config::External::File::Project do ...@@ -118,7 +119,7 @@ RSpec.describe Gitlab::Ci::Config::External::File::Project do
end end
it 'returns false' do it 'returns false' do
expect(project_file).not_to be_valid expect(valid?).to be_falsy
expect(project_file.error_message).to include("Project `#{project.full_path}` file `/file.yml` is empty!") expect(project_file.error_message).to include("Project `#{project.full_path}` file `/file.yml` is empty!")
end end
end end
...@@ -129,7 +130,7 @@ RSpec.describe Gitlab::Ci::Config::External::File::Project do ...@@ -129,7 +130,7 @@ RSpec.describe Gitlab::Ci::Config::External::File::Project do
end end
it 'returns false' do it 'returns false' do
expect(project_file).not_to be_valid expect(valid?).to be_falsy
expect(project_file.error_message).to include("Project `#{project.full_path}` reference `I-Do-Not-Exist` does not exist!") expect(project_file.error_message).to include("Project `#{project.full_path}` reference `I-Do-Not-Exist` does not exist!")
end end
end end
...@@ -140,7 +141,7 @@ RSpec.describe Gitlab::Ci::Config::External::File::Project do ...@@ -140,7 +141,7 @@ RSpec.describe Gitlab::Ci::Config::External::File::Project do
end end
it 'returns false' do it 'returns false' do
expect(project_file).not_to be_valid expect(valid?).to be_falsy
expect(project_file.error_message).to include("Project `#{project.full_path}` file `/invalid-file.yml` does not exist!") expect(project_file.error_message).to include("Project `#{project.full_path}` file `/invalid-file.yml` does not exist!")
end end
end end
...@@ -151,7 +152,7 @@ RSpec.describe Gitlab::Ci::Config::External::File::Project do ...@@ -151,7 +152,7 @@ RSpec.describe Gitlab::Ci::Config::External::File::Project do
end end
it 'returns false' do it 'returns false' do
expect(project_file).not_to be_valid expect(valid?).to be_falsy
expect(project_file.error_message).to include('Included file `/invalid-file` does not have YAML extension!') expect(project_file.error_message).to include('Included file `/invalid-file` does not have YAML extension!')
end end
end end
......
...@@ -53,22 +53,23 @@ RSpec.describe Gitlab::Ci::Config::External::File::Remote do ...@@ -53,22 +53,23 @@ RSpec.describe Gitlab::Ci::Config::External::File::Remote do
end end
describe "#valid?" do describe "#valid?" do
subject(:valid?) do
remote_file.validate!
remote_file.valid?
end
context 'when is a valid remote url' do context 'when is a valid remote url' do
before do before do
stub_full_request(location).to_return(body: remote_file_content) stub_full_request(location).to_return(body: remote_file_content)
end end
it 'returns true' do it { is_expected.to be_truthy }
expect(remote_file.valid?).to be_truthy
end
end end
context 'with an irregular url' do context 'with an irregular url' do
let(:location) { 'not-valid://gitlab.com/gitlab-org/gitlab-foss/blob/1234/.gitlab-ci-1.yml' } let(:location) { 'not-valid://gitlab.com/gitlab-org/gitlab-foss/blob/1234/.gitlab-ci-1.yml' }
it 'returns false' do it { is_expected.to be_falsy }
expect(remote_file.valid?).to be_falsy
end
end end
context 'with a timeout' do context 'with a timeout' do
...@@ -76,25 +77,19 @@ RSpec.describe Gitlab::Ci::Config::External::File::Remote do ...@@ -76,25 +77,19 @@ RSpec.describe Gitlab::Ci::Config::External::File::Remote do
allow(Gitlab::HTTP).to receive(:get).and_raise(Timeout::Error) allow(Gitlab::HTTP).to receive(:get).and_raise(Timeout::Error)
end end
it 'is falsy' do it { is_expected.to be_falsy }
expect(remote_file.valid?).to be_falsy
end
end end
context 'when is not a yaml file' do context 'when is not a yaml file' do
let(:location) { 'https://asdasdasdaj48ggerexample.com' } let(:location) { 'https://asdasdasdaj48ggerexample.com' }
it 'is falsy' do it { is_expected.to be_falsy }
expect(remote_file.valid?).to be_falsy
end
end end
context 'with an internal url' do context 'with an internal url' do
let(:location) { 'http://localhost:8080' } let(:location) { 'http://localhost:8080' }
it 'is falsy' do it { is_expected.to be_falsy }
expect(remote_file.valid?).to be_falsy
end
end end
end end
...@@ -141,7 +136,10 @@ RSpec.describe Gitlab::Ci::Config::External::File::Remote do ...@@ -141,7 +136,10 @@ RSpec.describe Gitlab::Ci::Config::External::File::Remote do
end end
describe "#error_message" do describe "#error_message" do
subject { remote_file.error_message } subject(:error_message) do
remote_file.validate!
remote_file.error_message
end
context 'when remote file location is not valid' do context 'when remote file location is not valid' do
let(:location) { 'not-valid://gitlab.com/gitlab-org/gitlab-foss/blob/1234/.gitlab-ci-1.yml' } let(:location) { 'not-valid://gitlab.com/gitlab-org/gitlab-foss/blob/1234/.gitlab-ci-1.yml' }
......
...@@ -45,19 +45,22 @@ RSpec.describe Gitlab::Ci::Config::External::File::Template do ...@@ -45,19 +45,22 @@ RSpec.describe Gitlab::Ci::Config::External::File::Template do
end end
describe "#valid?" do describe "#valid?" do
subject(:valid?) do
template_file.validate!
template_file.valid?
end
context 'when is a valid template name' do context 'when is a valid template name' do
let(:template) { 'Auto-DevOps.gitlab-ci.yml' } let(:template) { 'Auto-DevOps.gitlab-ci.yml' }
it 'returns true' do it { is_expected.to be_truthy }
expect(template_file).to be_valid
end
end end
context 'with invalid template name' do context 'with invalid template name' do
let(:template) { 'Template.yml' } let(:template) { 'Template.yml' }
it 'returns false' do it 'returns false' do
expect(template_file).not_to be_valid expect(valid?).to be_falsy
expect(template_file.error_message).to include('Template file `Template.yml` is not a valid location!') expect(template_file.error_message).to include('Template file `Template.yml` is not a valid location!')
end end
end end
...@@ -66,7 +69,7 @@ RSpec.describe Gitlab::Ci::Config::External::File::Template do ...@@ -66,7 +69,7 @@ RSpec.describe Gitlab::Ci::Config::External::File::Template do
let(:template) { 'I-Do-Not-Have-This-Template.gitlab-ci.yml' } let(:template) { 'I-Do-Not-Have-This-Template.gitlab-ci.yml' }
it 'returns false' do it 'returns false' do
expect(template_file).not_to be_valid expect(valid?).to be_falsy
expect(template_file.error_message).to include('Included file `I-Do-Not-Have-This-Template.gitlab-ci.yml` is empty or does not exist!') expect(template_file.error_message).to include('Included file `I-Do-Not-Have-This-Template.gitlab-ci.yml` is empty or does not exist!')
end end
end end
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment