File: runner_policy_shared_examples.rb

package info (click to toggle)
gitlab 17.6.5-19
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 629,368 kB
  • sloc: ruby: 1,915,304; javascript: 557,307; sql: 60,639; xml: 6,509; sh: 4,567; makefile: 1,239; python: 406
file content (286 lines) | stat: -rw-r--r-- 9,111 bytes parent folder | download
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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
# frozen_string_literal: true

RSpec.shared_examples 'a policy allowing reading instance runner/runner manager depending on runner sharing' do
    |ability|
  context 'with instance runner' do
    using RSpec::Parameterized::TableSyntax

    where(:shared_runners_enabled_on_group, :shared_runners_enabled_on_project, :expect_can_read) do
      false  | false  | false
      false  | true   | true
      true   | false  | true
      true   | true   | true
    end

    with_them do
      let(:runner) { instance_runner }

      before do
        group.update!(shared_runners_enabled: shared_runners_enabled_on_group)
        project.update!(shared_runners_enabled: shared_runners_enabled_on_project)
      end

      specify do
        if expect_can_read
          expect_allowed ability
        else
          expect_disallowed ability
        end
      end
    end
  end
end

RSpec.shared_examples 'a policy allowing reading group runner/runner manager depending on runner sharing' do
    |ability, user_role|
  let(:group_runners_enabled_on_project) { true }

  before do
    project.update!(group_runners_enabled: group_runners_enabled_on_project)
  end

  context 'with group runner' do
    let(:runner) { group_runner }

    # NOTE: The user is allowed to read the runner/runner manager because:
    # - the user is a maintainer+ in the runner's group
    # - the user is a maintainer+ in `group/subgroup/project`, and the runner is shared to that project
    it { expect_allowed ability }

    context 'with sharing of group runners disabled' do
      let(:group_runners_enabled_on_project) { false }

      it { expect_allowed ability }
    end

    context 'when user belongs to subgroup only' do
      let_it_be(:subgroup_member) do
        create(:user).tap { |subgroup_member| subgroup.add_member(subgroup_member, user_role) }
      end

      let(:user) { subgroup_member }

      context 'with runner visible to group project' do
        # NOTE: The user is allowed to read the runner/runner manager because the user is a maintainer+
        # in `group/subgroup/project`, and the runner is shared to that project
        it { expect_allowed ability }

        context 'with sharing of group runners disabled' do
          let(:group_runners_enabled_on_project) { false }

          it { expect_disallowed ability }
        end
      end

      context 'without projects in group' do
        let(:runner) { runner_on_group_without_project }

        it { expect_disallowed ability }
      end
    end

    context "when user is not #{user_role} in associated group" do
      let_it_be(:user_with_role) { create(:user) }

      let(:user) { user_with_role }

      it { expect_disallowed ability }

      context "when user is #{user_role} in a group invited to group as #{user_role}" do
        let_it_be(:invited_group) { create(:group, name: "#{user_role}s", path: "#{user_role}s") }

        before_all do
          invited_group.add_member(user_with_role, user_role)
          create(:group_group_link, :maintainer, shared_group: group, shared_with_group: invited_group)
        end

        it { expect_allowed ability }
      end

      context "when user is a reporter in a group invited to group as #{user_role}" do
        let_it_be(:invited_group) do
          create(:group, name: "#{user_role}s", path: "#{user_role}s", reporters: user_with_role)
        end

        before_all do
          create(:group_group_link, user_role, shared_group: group, shared_with_group: invited_group)
        end

        it { expect_disallowed ability }
      end
    end
  end

  context 'when runner is in subgroup' do
    let(:runner) { subgroup_runner }

    # NOTE: The user is allowed to read the runner/runner manager because the user is a maintainer+ in
    # `group/subgroup/project`, and the runner is shared to that project
    it { expect_allowed ability }

    context 'with sharing of group runners disabled' do
      let(:group_runners_enabled_on_project) { false }

      it { expect_disallowed ability }
    end
  end
end

RSpec.shared_examples 'does not allow reading runners/runner managers on any scope' do |ability|
  context 'with instance runner' do
    let(:runner) { instance_runner }

    it { expect_disallowed ability }

    context 'with shared runners disabled for groups and projects' do
      before do
        group.update!(shared_runners_enabled: false)
        project.update!(shared_runners_enabled: false)
      end

      it { expect_disallowed ability }
    end
  end

  context 'with group runner' do
    let(:runner) { group_runner }

    it { expect_disallowed ability }

    context 'with group invited as maintainer to group containing runner' do
      let_it_be(:invited_group) { create(:group) }
      let_it_be(:runner) { create(:ci_runner, :group, :with_runner_manager, groups: [invited_group]) }

      before_all do
        create(:group_group_link, :maintainer, shared_group: group, shared_with_group: invited_group)
      end

      it { expect_disallowed ability }
    end

    context 'with sharing of group runners disabled' do
      before do
        project.update!(group_runners_enabled: false)
      end

      it { expect_disallowed ability }
    end
  end

  context 'with project runner' do
    let(:runner) { project_runner }

    it { expect_disallowed ability }
  end
end

RSpec.shared_examples 'runner read policy' do |ability|
  let_it_be(:guest) { create(:user) }
  let_it_be(:reporter) { create(:user) }
  let_it_be(:developer) { create(:user) }
  let_it_be(:maintainer) { create(:user) }

  let_it_be_with_reload(:group) do
    create(:group, name: 'top-level', path: 'top-level',
      guests: guest, reporters: reporter, developers: developer, maintainers: maintainer, owners: owner)
  end

  let_it_be_with_reload(:subgroup) { create(:group, name: 'subgroup', path: 'subgroup', parent: group) }
  let_it_be_with_reload(:project) { create(:project, group: subgroup) }
  let_it_be_with_reload(:group_without_project) { create(:group, name: 'top-level2', path: 'top-level2') }

  let_it_be(:instance_runner) { create(:ci_runner, :instance, :with_runner_manager) }
  let_it_be(:group_runner) { create(:ci_runner, :group, :with_runner_manager, groups: [group]) }
  let_it_be(:subgroup_runner) { create(:ci_runner, :group, :with_runner_manager, groups: [subgroup]) }
  let_it_be(:project_runner) { create(:ci_runner, :project, :with_runner_manager, projects: [project]) }
  let_it_be(:runner_on_group_without_project) do
    create(:ci_runner, :group, :with_runner_manager, groups: [group_without_project])
  end

  context 'without access' do
    let_it_be(:user) { create(:user) }

    it_behaves_like 'does not allow reading runners/runner managers on any scope', ability
  end

  context 'with guest access' do
    let(:user) { guest }

    it_behaves_like 'does not allow reading runners/runner managers on any scope', ability
  end

  context 'with reporter access' do
    let(:user) { reporter }

    it_behaves_like 'does not allow reading runners/runner managers on any scope', ability
  end

  context 'with developer access' do
    let(:user) { developer }

    it_behaves_like 'does not allow reading runners/runner managers on any scope', ability
  end

  context 'with maintainer access' do
    let(:user) { maintainer }

    it_behaves_like 'a policy allowing reading instance runner/runner manager depending on runner sharing', ability

    it_behaves_like 'a policy allowing reading group runner/runner manager depending on runner sharing',
      ability, :maintainer

    context 'with project runner' do
      let(:runner) { project_runner }

      it { expect_allowed ability }

      context 'when user is not maintainer in parent group' do
        let_it_be(:maintainers_group_maintainer) { create(:user) }
        let_it_be_with_reload(:maintainers_group) { create(:group, name: 'maintainers', path: 'maintainers') }

        let(:user) { maintainers_group_maintainer }

        before_all do
          create(:project_group_link, :maintainer, group: maintainers_group, project: project)
          maintainers_group.add_reporter(maintainers_group_maintainer)
        end

        it { expect_disallowed ability }

        context 'when user is maintainer in a group invited to project as maintainer' do
          before_all do
            maintainers_group.add_maintainer(maintainers_group_maintainer)
          end

          it { expect_allowed ability }
        end
      end
    end
  end

  context 'with owner access' do
    let(:user) { owner }

    it_behaves_like 'a policy allowing reading instance runner/runner manager depending on runner sharing', ability

    context 'with group runner' do
      let(:runner) { group_runner }

      it { expect_allowed ability }

      context 'with sharing of group runners disabled' do
        before do
          project.update!(group_runners_enabled: false)
        end

        it { expect_allowed ability }
      end
    end

    context 'with project runner' do
      let(:runner) { project_runner }

      it { expect_allowed ability }
    end
  end
end