summaryrefslogtreecommitdiff
path: root/spec/lib/gitlab/untrusted_regexp/ruby_syntax_spec.rb
blob: 68402e64012d3781e6cb68ce74fc1dc2a39b0a99 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
# frozen_string_literal: true

require 'fast_spec_helper'
require 'support/shared_examples/malicious_regexp_shared_examples'
require 'support/helpers/stub_feature_flags'

describe Gitlab::UntrustedRegexp::RubySyntax do
  describe '.matches_syntax?' do
    it 'returns true if regexp is valid' do
      expect(described_class.matches_syntax?('/some .* thing/'))
        .to be true
    end

    it 'returns true if regexp is invalid, but resembles regexp' do
      expect(described_class.matches_syntax?('/some ( thing/'))
        .to be true
    end
  end

  describe '.valid?' do
    it 'returns true if regexp is valid' do
      expect(described_class.valid?('/some .* thing/'))
        .to be true
    end

    it 'returns false if regexp is invalid' do
      expect(described_class.valid?('/some ( thing/'))
        .to be false
    end
  end

  describe '.fabricate' do
    context 'when regexp is valid' do
      it 'fabricates regexp without flags' do
        expect(described_class.fabricate('/some .* thing/')).not_to be_nil
      end
    end

    context 'when regexp is empty' do
      it 'fabricates regexp correctly' do
        expect(described_class.fabricate('//')).not_to be_nil
      end
    end

    context 'when regexp is a raw pattern' do
      it 'returns error' do
        expect(described_class.fabricate('some .* thing')).to be_nil
      end
    end
  end

  describe '.fabricate!' do
    context 'safe regexp is used' do
      context 'when regexp is using /regexp/ scheme with flags' do
        it 'fabricates regexp with a single flag' do
          regexp = described_class.fabricate!('/something/i')

          expect(regexp).to eq Gitlab::UntrustedRegexp.new('(?i)something')
          expect(regexp.scan('SOMETHING')).to be_one
        end

        it 'fabricates regexp with multiple flags' do
          regexp = described_class.fabricate!('/something/im')

          expect(regexp).to eq Gitlab::UntrustedRegexp.new('(?im)something')
        end

        it 'fabricates regexp without flags' do
          regexp = described_class.fabricate!('/something/')

          expect(regexp).to eq Gitlab::UntrustedRegexp.new('something')
        end
      end
    end

    context 'when unsafe regexp is used' do
      include StubFeatureFlags

      before do
        stub_feature_flags(allow_unsafe_ruby_regexp: true)

        allow(Gitlab::UntrustedRegexp).to receive(:new).and_raise(RegexpError)
      end

      context 'when no fallback is enabled' do
        it 'raises an exception' do
          expect { described_class.fabricate!('/something/') }
            .to raise_error(RegexpError)
        end
      end

      context 'when fallback is used' do
        it 'fabricates regexp with a single flag' do
          regexp = described_class.fabricate!('/something/i', fallback: true)

          expect(regexp).to eq Regexp.new('something', Regexp::IGNORECASE)
        end

        it 'fabricates regexp with multiple flags' do
          regexp = described_class.fabricate!('/something/im', fallback: true)

          expect(regexp).to eq Regexp.new('something', Regexp::IGNORECASE | Regexp::MULTILINE)
        end

        it 'fabricates regexp without flags' do
          regexp = described_class.fabricate!('/something/', fallback: true)

          expect(regexp).to eq Regexp.new('something')
        end
      end
    end

    context 'when regexp is a raw pattern' do
      it 'raises an error' do
        expect { described_class.fabricate!('some .* thing') }
          .to raise_error(RegexpError)
      end
    end
  end
end