diff options
author | Douwe Maan <douwe@gitlab.com> | 2017-06-14 14:58:52 +0000 |
---|---|---|
committer | James Edwards-Jones <jedwardsjones@gitlab.com> | 2017-07-19 16:43:55 +0100 |
commit | 5ba0577326c4f7b91bf6cfd1fde29a90ff11561d (patch) | |
tree | aa4f8f973726ed1bed05f066c24d72ac6b10a98c /spec | |
parent | 4c9da11444df4a83fc228591d8e920ec046bc45d (diff) | |
download | gitlab-ce-5ba0577326c4f7b91bf6cfd1fde29a90ff11561d.tar.gz |
Merge branch '24570-use-re2-for-user-supplied-regexp-9-0' into 'security-9-0'
[security-9-0] Use re2 for user-supplied regexps
See merge request !2122
Diffstat (limited to 'spec')
-rw-r--r-- | spec/lib/gitlab/route_map_spec.rb | 13 | ||||
-rw-r--r-- | spec/lib/gitlab/untrusted_regexp_spec.rb | 80 | ||||
-rw-r--r-- | spec/models/ci/build_spec.rb | 24 | ||||
-rw-r--r-- | spec/support/malicious_regexp_shared_examples.rb | 8 |
4 files changed, 120 insertions, 5 deletions
diff --git a/spec/lib/gitlab/route_map_spec.rb b/spec/lib/gitlab/route_map_spec.rb index 2370f56a613..566266242d1 100644 --- a/spec/lib/gitlab/route_map_spec.rb +++ b/spec/lib/gitlab/route_map_spec.rb @@ -55,6 +55,19 @@ describe Gitlab::RouteMap, lib: true do end describe '#public_path_for_source_path' do + context 'malicious regexp' do + include_examples 'malicious regexp' + + subject do + map = described_class.new(<<-"MAP".strip_heredoc) + - source: '#{malicious_regexp}' + public: '/' + MAP + + map.public_path_for_source_path(malicious_text) + end + end + subject do described_class.new(<<-'MAP'.strip_heredoc) # Team data diff --git a/spec/lib/gitlab/untrusted_regexp_spec.rb b/spec/lib/gitlab/untrusted_regexp_spec.rb new file mode 100644 index 00000000000..66045917cb3 --- /dev/null +++ b/spec/lib/gitlab/untrusted_regexp_spec.rb @@ -0,0 +1,80 @@ +require 'spec_helper' + +describe Gitlab::UntrustedRegexp do + describe '#initialize' do + subject { described_class.new(pattern) } + + context 'invalid regexp' do + let(:pattern) { '[' } + + it { expect { subject }.to raise_error(RegexpError) } + end + end + + describe '#replace_all' do + it 'replaces all instances of the match in a string' do + result = described_class.new('foo').replace_all('foo bar foo', 'oof') + + expect(result).to eq('oof bar oof') + end + end + + describe '#replace' do + it 'replaces the first instance of the match in a string' do + result = described_class.new('foo').replace('foo bar foo', 'oof') + + expect(result).to eq('oof bar foo') + end + end + + describe '#===' do + it 'returns true for a match' do + result = described_class.new('foo') === 'a foo here' + + expect(result).to be_truthy + end + + it 'returns false for no match' do + result = described_class.new('foo') === 'a bar here' + + expect(result).to be_falsy + end + end + + describe '#scan' do + subject { described_class.new(regexp).scan(text) } + context 'malicious regexp' do + let(:text) { malicious_text } + let(:regexp) { malicious_regexp } + + include_examples 'malicious regexp' + end + + context 'no capture group' do + let(:regexp) { '.+' } + let(:text) { 'foo' } + + it 'returns the whole match' do + is_expected.to eq(['foo']) + end + end + + context 'one capture group' do + let(:regexp) { '(f).+' } + let(:text) { 'foo' } + + it 'returns the captured part' do + is_expected.to eq([%w[f]]) + end + end + + context 'two capture groups' do + let(:regexp) { '(f).(o)' } + let(:text) { 'foo' } + + it 'returns the captured parts' do + is_expected.to eq([%w[f o]]) + end + end + end +end diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb index 8dbcf50ee0c..9128c3aaabd 100644 --- a/spec/models/ci/build_spec.rb +++ b/spec/models/ci/build_spec.rb @@ -533,35 +533,49 @@ describe Ci::Build, :models do end describe '#extract_coverage' do + subject { build.extract_coverage(data, regex) } + context 'valid content & regex' do - subject { build.extract_coverage('Coverage 1033 / 1051 LOC (98.29%) covered', '\(\d+.\d+\%\) covered') } + let(:data) { 'Coverage 1033 / 1051 LOC (98.29%) covered' } + let(:regex) { '\(\d+.\d+\%\) covered' } it { is_expected.to eq(98.29) } end context 'valid content & bad regex' do - subject { build.extract_coverage('Coverage 1033 / 1051 LOC (98.29%) covered', 'very covered') } + let(:data) { 'Coverage 1033 / 1051 LOC (98.29%) covered\n' } + let(:regex) { 'very covered' } it { is_expected.to be_nil } end context 'no coverage content & regex' do - subject { build.extract_coverage('No coverage for today :sad:', '\(\d+.\d+\%\) covered') } + let(:data) { 'No coverage for today :sad:' } + let(:regex) { '\(\d+.\d+\%\) covered' } it { is_expected.to be_nil } end context 'multiple results in content & regex' do - subject { build.extract_coverage(' (98.39%) covered. (98.29%) covered', '\(\d+.\d+\%\) covered') } + let(:data) { ' (98.39%) covered. (98.29%) covered' } + let(:regex) { '\(\d+.\d+\%\) covered' } it { is_expected.to eq(98.29) } end context 'using a regex capture' do - subject { build.extract_coverage('TOTAL 9926 3489 65%', 'TOTAL\s+\d+\s+\d+\s+(\d{1,3}\%)') } + let(:data) { 'TOTAL 9926 3489 65%' } + let(:regex) { 'TOTAL\s+\d+\s+\d+\s+(\d{1,3}\%)' } it { is_expected.to eq(65) } end + + context 'malicious regexp' do + let(:data) { malicious_text } + let(:regex) { malicious_regexp } + + include_examples 'malicious regexp' + end end describe '#first_pending' do diff --git a/spec/support/malicious_regexp_shared_examples.rb b/spec/support/malicious_regexp_shared_examples.rb new file mode 100644 index 00000000000..ac5d22298bb --- /dev/null +++ b/spec/support/malicious_regexp_shared_examples.rb @@ -0,0 +1,8 @@ +shared_examples 'malicious regexp' do + let(:malicious_text) { 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa!' } + let(:malicious_regexp) { '(?i)^(([a-z])+.)+[A-Z]([a-z])+$' } + + it 'takes under a second' do + expect { Timeout.timeout(1) { subject } }.not_to raise_error + end +end |