Limit extendable CI/CD config entry nesting levels
This commit is contained in:
parent
d2f46c3025
commit
afbe5490f0
3 changed files with 47 additions and 9 deletions
|
@ -8,6 +8,7 @@ module Gitlab
|
|||
ExtensionError = Class.new(StandardError)
|
||||
InvalidExtensionError = Class.new(ExtensionError)
|
||||
CircularDependencyError = Class.new(ExtensionError)
|
||||
NestingTooDeepError = Class.new(ExtensionError)
|
||||
|
||||
def initialize(hash)
|
||||
@hash = hash.to_h.deep_dup
|
||||
|
|
|
@ -3,6 +3,8 @@ module Gitlab
|
|||
class Config
|
||||
module Extendable
|
||||
class Entry
|
||||
MAX_NESTING_LEVELS = 10
|
||||
|
||||
attr_reader :key
|
||||
|
||||
def initialize(key, context, parent = nil)
|
||||
|
@ -10,7 +12,9 @@ module Gitlab
|
|||
@context = context
|
||||
@parent = parent
|
||||
|
||||
raise StandardError, 'Invalid entry key!' unless @context.key?(@key)
|
||||
unless @context.key?(@key)
|
||||
raise StandardError, 'Invalid entry key!'
|
||||
end
|
||||
end
|
||||
|
||||
def extensible?
|
||||
|
@ -31,8 +35,8 @@ module Gitlab
|
|||
value.fetch(:extends).to_s.to_sym if extensible?
|
||||
end
|
||||
|
||||
def path
|
||||
Array(@parent&.path).compact.push(key)
|
||||
def ancestors
|
||||
@ancestors ||= Array(@parent&.ancestors) + Array(@parent&.key)
|
||||
end
|
||||
|
||||
def extend!
|
||||
|
@ -48,6 +52,11 @@ module Gitlab
|
|||
"Invalid base hash in extended `#{key}`!"
|
||||
end
|
||||
|
||||
if nesting_too_deep?
|
||||
raise Extendable::Collection::NestingTooDeepError,
|
||||
"`extends` nesting too deep in `#{key}`!"
|
||||
end
|
||||
|
||||
if circular_dependency?
|
||||
raise Extendable::Collection::CircularDependencyError,
|
||||
"Circular dependency detected in extended `#{key}`!"
|
||||
|
@ -58,8 +67,12 @@ module Gitlab
|
|||
|
||||
private
|
||||
|
||||
def nesting_too_deep?
|
||||
ancestors.count > MAX_NESTING_LEVELS
|
||||
end
|
||||
|
||||
def circular_dependency?
|
||||
path.count(key) > 1
|
||||
ancestors.include?(key)
|
||||
end
|
||||
|
||||
def unknown_extension?
|
||||
|
|
|
@ -62,12 +62,17 @@ describe Gitlab::Ci::Config::Extendable::Entry do
|
|||
end
|
||||
end
|
||||
|
||||
describe '#path' do
|
||||
it 'returns inheritance chain path' do
|
||||
parent = described_class.new(:test, test: { extends: 'something' })
|
||||
child = described_class.new(:job, { job: { script: 'something' } }, parent)
|
||||
describe '#ancestors' do
|
||||
let(:parent) do
|
||||
described_class.new(:test, test: { extends: 'something' })
|
||||
end
|
||||
|
||||
expect(child.path).to eq [:test, :job]
|
||||
let(:child) do
|
||||
described_class.new(:job, { job: { script: 'something' } }, parent)
|
||||
end
|
||||
|
||||
it 'returns ancestors keys' do
|
||||
expect(child.ancestors).to eq [:test]
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -196,5 +201,24 @@ describe Gitlab::Ci::Config::Extendable::Entry do
|
|||
.to raise_error(StandardError, /Circular dependency detected/)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when nesting level is too deep' do
|
||||
before do
|
||||
stub_const("#{described_class}::MAX_NESTING_LEVELS", 0)
|
||||
end
|
||||
|
||||
let(:hash) do
|
||||
{
|
||||
first: { script: 'my value' },
|
||||
second: { extends: 'first' },
|
||||
test: { extends: 'second' }
|
||||
}
|
||||
end
|
||||
|
||||
it 'raises an error' do
|
||||
expect { subject.extend! }
|
||||
.to raise_error(Gitlab::Ci::Config::Extendable::Collection::NestingTooDeepError)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue