summaryrefslogtreecommitdiff
path: root/spec
diff options
context:
space:
mode:
authorDouwe Maan <douwe@gitlab.com>2017-06-14 14:58:52 +0000
committerJames Edwards-Jones <jedwardsjones@gitlab.com>2017-07-19 16:43:55 +0100
commit5ba0577326c4f7b91bf6cfd1fde29a90ff11561d (patch)
treeaa4f8f973726ed1bed05f066c24d72ac6b10a98c /spec
parent4c9da11444df4a83fc228591d8e920ec046bc45d (diff)
downloadgitlab-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.rb13
-rw-r--r--spec/lib/gitlab/untrusted_regexp_spec.rb80
-rw-r--r--spec/models/ci/build_spec.rb24
-rw-r--r--spec/support/malicious_regexp_shared_examples.rb8
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