diff --git a/app/validators/json_schemas/catalog_resource_component_inputs.json b/app/validators/json_schemas/catalog_resource_component_inputs.json index 014a52d4f1bbb51904a9ff2672fdcc76c426950d..830bf68483882c5d0f1c49e2ed2ecba3e507bea5 100644 --- a/app/validators/json_schemas/catalog_resource_component_inputs.json +++ b/app/validators/json_schemas/catalog_resource_component_inputs.json @@ -15,6 +15,9 @@ "boolean" ] }, + "regex": { + "type": "string" + }, "^type$": { "type": "string" } diff --git a/lib/gitlab/ci/config/header/input.rb b/lib/gitlab/ci/config/header/input.rb index ed293cb6f4b6ccdec176cd7f90c6a5ed71327ec2..dcb960064597376adb0a3791e0e19491c2f75a9a 100644 --- a/lib/gitlab/ci/config/header/input.rb +++ b/lib/gitlab/ci/config/header/input.rb @@ -11,14 +11,17 @@ class Input < ::Gitlab::Config::Entry::Node include ::Gitlab::Config::Entry::Validatable include ::Gitlab::Config::Entry::Attributable - attributes :default, :description, :type, prefix: :input + ALLOWED_KEYS = %i[default description regex type].freeze + + attributes ALLOWED_KEYS, prefix: :input validations do - validates :config, type: Hash, allowed_keys: [:default, :type, :description] + validates :config, type: Hash, allowed_keys: ALLOWED_KEYS validates :key, alphanumeric: true validates :input_default, alphanumeric: true, allow_nil: true - validates :input_type, allow_nil: true, allowed_values: Interpolation::Inputs.input_types validates :input_description, alphanumeric: true, allow_nil: true + validates :input_regex, type: String, allow_nil: true + validates :input_type, allow_nil: true, allowed_values: Interpolation::Inputs.input_types end end end diff --git a/lib/gitlab/ci/config/interpolation/inputs/base_input.rb b/lib/gitlab/ci/config/interpolation/inputs/base_input.rb index 5648c4d31eaab35f35eb7692f8733106b35ecacf..ba5197766359f2feb1328a44017911c39d061e5c 100644 --- a/lib/gitlab/ci/config/interpolation/inputs/base_input.rb +++ b/lib/gitlab/ci/config/interpolation/inputs/base_input.rb @@ -62,7 +62,15 @@ def validate! end # validate provided value - error("provided value is not a #{self.class.type_name}") unless valid_value?(actual_value) + return error("provided value is not a #{self.class.type_name}") unless valid_value?(actual_value) + + validate_regex! + end + + def validate_regex! + return unless spec.key?(:regex) + + error('RegEx validation can only be used with string inputs') end def error(message) diff --git a/lib/gitlab/ci/config/interpolation/inputs/string_input.rb b/lib/gitlab/ci/config/interpolation/inputs/string_input.rb index 39870582d0c0d33f41ad06a11a55705009ab44e8..9b695d168da46b4bc78c32d3f2d7199f399a43b3 100644 --- a/lib/gitlab/ci/config/interpolation/inputs/string_input.rb +++ b/lib/gitlab/ci/config/interpolation/inputs/string_input.rb @@ -25,6 +25,19 @@ def self.type_name def valid_value?(value) value.nil? || value.is_a?(String) end + + private + + def validate_regex! + return unless spec.key?(:regex) + return if actual_value.match?(spec[:regex]) + + if value.nil? + error('default value does not match required RegEx pattern') + else + error('provided value does not match required RegEx pattern') + end + end end end end diff --git a/spec/lib/gitlab/ci/config/header/input_spec.rb b/spec/lib/gitlab/ci/config/header/input_spec.rb index b4e02c2b005012f743ddac10ae447fecdfc56d59..5d1fa4a8e6ef966d5eaa56a15ddb519b3d63e66d 100644 --- a/spec/lib/gitlab/ci/config/header/input_spec.rb +++ b/spec/lib/gitlab/ci/config/header/input_spec.rb @@ -68,6 +68,12 @@ end end + context 'when the input has RegEx validation' do + let(:input_hash) { { regex: '\w+' } } + + it_behaves_like 'a valid input' + end + context 'when given an invalid type' do let(:input_hash) { { type: 'datetime' } } let(:expected_errors) { ['foo input type unknown value: datetime'] } @@ -90,4 +96,11 @@ it_behaves_like 'an invalid input' end + + context 'when RegEx validation value is not a string' do + let(:input_hash) { { regex: [] } } + let(:expected_errors) { ['foo input regex should be a string'] } + + it_behaves_like 'an invalid input' + end end diff --git a/spec/lib/gitlab/ci/config/interpolation/inputs_spec.rb b/spec/lib/gitlab/ci/config/interpolation/inputs_spec.rb index ea06f181fa4a5dd45fdeb16ecf5fcf1c43dd3955..c7ec0a341192300903254f37ef60a87ea0070382 100644 --- a/spec/lib/gitlab/ci/config/interpolation/inputs_spec.rb +++ b/spec/lib/gitlab/ci/config/interpolation/inputs_spec.rb @@ -57,6 +57,16 @@ { default_boolean_input: { default: true, type: 'boolean' } }, {}, { default_boolean_input: true } + ], + [ + { test_input: { regex: '^input_value$' } }, + { test_input: 'input_value' }, + { test_input: 'input_value' } + ], + [ + { test_input: { regex: '^input_value$', default: 'input_value' } }, + {}, + { test_input: 'input_value' } ] ] end @@ -123,6 +133,21 @@ { default_boolean_input: { default: 'string', type: 'boolean' } }, {}, ['`default_boolean_input` input: default value is not a boolean'] + ], + [ + { test_input: { regex: '^input_value$' } }, + { test_input: 'input' }, + ['`test_input` input: provided value does not match required RegEx pattern'] + ], + [ + { test_input: { regex: '^input_value$', default: 'default' } }, + {}, + ['`test_input` input: default value does not match required RegEx pattern'] + ], + [ + { test_input: { regex: '^input_value$', type: 'number' } }, + { test_input: 999 }, + ['`test_input` input: RegEx validation can only be used with string inputs'] ] ] end