1# frozen_string_literal: true
2
3require 'spec_helper'
4
5RSpec.describe IssuePolicy do
6  include ExternalAuthorizationServiceHelpers
7
8  let(:guest) { create(:user) }
9  let(:author) { create(:user) }
10  let(:assignee) { create(:user) }
11  let(:reporter) { create(:user) }
12  let(:group) { create(:group, :public) }
13  let(:reporter_from_group_link) { create(:user) }
14  let(:non_member) { create(:user) }
15  let(:support_bot) { User.support_bot }
16
17  def permissions(user, issue)
18    described_class.new(user, issue)
19  end
20
21  shared_examples 'support bot with service desk enabled' do
22    before do
23      allow(::Gitlab::IncomingEmail).to receive(:enabled?) { true }
24      allow(::Gitlab::IncomingEmail).to receive(:supports_wildcard?) { true }
25
26      project.update!(service_desk_enabled: true)
27    end
28
29    it 'allows support_bot to read issues, create and set metadata on new issues' do
30      expect(permissions(support_bot, issue)).to be_allowed(:read_issue, :read_issue_iid, :update_issue, :admin_issue, :set_issue_metadata, :set_confidentiality)
31      expect(permissions(support_bot, issue_no_assignee)).to be_allowed(:read_issue, :read_issue_iid, :update_issue, :admin_issue, :set_issue_metadata, :set_confidentiality)
32      expect(permissions(support_bot, new_issue)).to be_allowed(:create_issue, :set_issue_metadata, :set_confidentiality)
33    end
34  end
35
36  shared_examples 'support bot with service desk disabled' do
37    it 'does not allow support_bot to read issues, create and set metadata on new issues' do
38      expect(permissions(support_bot, issue)).to be_disallowed(:read_issue, :read_issue_iid, :update_issue, :admin_issue, :set_issue_metadata, :set_confidentiality)
39      expect(permissions(support_bot, issue_no_assignee)).to be_disallowed(:read_issue, :read_issue_iid, :update_issue, :admin_issue, :set_issue_metadata, :set_confidentiality)
40      expect(permissions(support_bot, new_issue)).to be_disallowed(:create_issue, :set_issue_metadata, :set_confidentiality)
41    end
42  end
43
44  context 'a private project' do
45    let(:project) { create(:project, :private) }
46    let(:issue) { create(:issue, project: project, assignees: [assignee], author: author) }
47    let(:issue_no_assignee) { create(:issue, project: project) }
48    let(:new_issue) { build(:issue, project: project, assignees: [assignee], author: author) }
49
50    before do
51      project.add_guest(guest)
52      project.add_guest(author)
53      project.add_guest(assignee)
54      project.add_reporter(reporter)
55
56      group.add_reporter(reporter_from_group_link)
57
58      create(:project_group_link, group: group, project: project)
59    end
60
61    it 'allows guests to read issues' do
62      expect(permissions(guest, issue)).to be_allowed(:read_issue, :read_issue_iid)
63      expect(permissions(guest, issue)).to be_disallowed(:update_issue, :admin_issue, :set_issue_metadata, :set_confidentiality)
64
65      expect(permissions(guest, issue_no_assignee)).to be_allowed(:read_issue, :read_issue_iid)
66      expect(permissions(guest, issue_no_assignee)).to be_disallowed(:update_issue, :admin_issue, :set_issue_metadata, :set_confidentiality)
67
68      expect(permissions(guest, new_issue)).to be_allowed(:create_issue, :set_issue_metadata, :set_confidentiality)
69    end
70
71    it 'allows reporters to read, update, and admin issues' do
72      expect(permissions(reporter, issue)).to be_allowed(:read_issue, :read_issue_iid, :update_issue, :admin_issue, :set_issue_metadata, :set_confidentiality)
73      expect(permissions(reporter, issue_no_assignee)).to be_allowed(:read_issue, :read_issue_iid, :update_issue, :admin_issue, :set_issue_metadata, :set_confidentiality)
74      expect(permissions(reporter, new_issue)).to be_allowed(:create_issue, :set_issue_metadata, :set_confidentiality)
75    end
76
77    it 'allows reporters from group links to read, update, and admin issues' do
78      expect(permissions(reporter_from_group_link, issue)).to be_allowed(:read_issue, :read_issue_iid, :update_issue, :admin_issue, :set_issue_metadata, :set_confidentiality)
79      expect(permissions(reporter_from_group_link, issue_no_assignee)).to be_allowed(:read_issue, :read_issue_iid, :update_issue, :admin_issue, :set_issue_metadata, :set_confidentiality)
80      expect(permissions(reporter_from_group_link, new_issue)).to be_allowed(:create_issue, :set_issue_metadata, :set_confidentiality)
81    end
82
83    it 'allows issue authors to read and update their issues' do
84      expect(permissions(author, issue)).to be_allowed(:read_issue, :read_issue_iid, :update_issue)
85      expect(permissions(author, issue)).to be_disallowed(:admin_issue, :set_issue_metadata, :set_confidentiality)
86
87      expect(permissions(author, issue_no_assignee)).to be_allowed(:read_issue, :read_issue_iid)
88      expect(permissions(author, issue_no_assignee)).to be_disallowed(:update_issue, :admin_issue, :set_issue_metadata, :set_confidentiality)
89
90      expect(permissions(author, new_issue)).to be_allowed(:create_issue, :set_issue_metadata, :set_confidentiality)
91    end
92
93    it 'allows issue assignees to read and update their issues' do
94      expect(permissions(assignee, issue)).to be_allowed(:read_issue, :read_issue_iid, :update_issue)
95      expect(permissions(assignee, issue)).to be_disallowed(:admin_issue, :set_issue_metadata, :set_confidentiality)
96
97      expect(permissions(assignee, issue_no_assignee)).to be_allowed(:read_issue, :read_issue_iid)
98      expect(permissions(assignee, issue_no_assignee)).to be_disallowed(:update_issue, :admin_issue, :set_issue_metadata, :set_confidentiality)
99
100      expect(permissions(assignee, new_issue)).to be_allowed(:create_issue, :set_issue_metadata, :set_confidentiality)
101    end
102
103    it 'does not allow non-members to read, update or create issues' do
104      expect(permissions(non_member, issue)).to be_disallowed(:read_issue, :read_issue_iid, :update_issue, :admin_issue, :set_issue_metadata, :set_confidentiality)
105      expect(permissions(non_member, issue_no_assignee)).to be_disallowed(:read_issue, :read_issue_iid, :update_issue, :admin_issue, :set_issue_metadata, :set_confidentiality)
106      expect(permissions(non_member, new_issue)).to be_disallowed(:create_issue, :set_issue_metadata, :set_confidentiality)
107    end
108
109    it_behaves_like 'support bot with service desk disabled'
110    it_behaves_like 'support bot with service desk enabled'
111
112    context 'with confidential issues' do
113      let(:confidential_issue) { create(:issue, :confidential, project: project, assignees: [assignee], author: author) }
114      let(:confidential_issue_no_assignee) { create(:issue, :confidential, project: project) }
115
116      it 'does not allow non-members to read confidential issues' do
117        expect(permissions(non_member, confidential_issue)).to be_disallowed(:read_issue, :read_issue_iid, :update_issue, :admin_issue)
118        expect(permissions(non_member, confidential_issue_no_assignee)).to be_disallowed(:read_issue, :read_issue_iid, :update_issue, :admin_issue, :set_issue_metadata, :set_confidentiality)
119      end
120
121      it 'does not allow guests to read confidential issues' do
122        expect(permissions(guest, confidential_issue)).to be_disallowed(:read_issue, :read_issue_iid, :update_issue, :admin_issue)
123        expect(permissions(guest, confidential_issue_no_assignee)).to be_disallowed(:read_issue, :read_issue_iid, :update_issue, :admin_issue, :set_issue_metadata, :set_confidentiality)
124      end
125
126      it 'allows reporters to read, update, and admin confidential issues' do
127        expect(permissions(reporter, confidential_issue)).to be_allowed(:read_issue, :read_issue_iid, :update_issue, :admin_issue, :set_issue_metadata, :set_confidentiality)
128        expect(permissions(reporter, confidential_issue_no_assignee)).to be_allowed(:read_issue, :read_issue_iid, :update_issue, :admin_issue, :set_issue_metadata, :set_confidentiality)
129      end
130
131      it 'allows reporters from group links to read, update, and admin confidential issues' do
132        expect(permissions(reporter_from_group_link, confidential_issue)).to be_allowed(:read_issue, :read_issue_iid, :update_issue, :admin_issue, :set_issue_metadata, :set_confidentiality)
133        expect(permissions(reporter_from_group_link, confidential_issue_no_assignee)).to be_allowed(:read_issue, :read_issue_iid, :update_issue, :admin_issue, :set_issue_metadata, :set_confidentiality)
134      end
135
136      it 'allows issue authors to read and update their confidential issues' do
137        expect(permissions(author, confidential_issue)).to be_allowed(:read_issue, :read_issue_iid, :update_issue)
138        expect(permissions(author, confidential_issue)).to be_disallowed(:admin_issue, :set_issue_metadata, :set_confidentiality)
139
140        expect(permissions(author, confidential_issue_no_assignee)).to be_disallowed(:read_issue, :read_issue_iid, :update_issue, :admin_issue)
141        expect(permissions(author, confidential_issue_no_assignee)).to be_disallowed(:admin_issue, :set_issue_metadata, :set_confidentiality)
142      end
143
144      it 'does not allow issue author to read or update confidential issue moved to an private project' do
145        confidential_issue.project = create(:project, :private)
146
147        expect(permissions(author, confidential_issue)).to be_disallowed(:read_issue, :read_issue_iid, :update_issue, :set_issue_metadata, :set_confidentiality)
148      end
149
150      it 'allows issue assignees to read and update their confidential issues' do
151        expect(permissions(assignee, confidential_issue)).to be_allowed(:read_issue, :read_issue_iid, :update_issue)
152        expect(permissions(assignee, confidential_issue)).to be_disallowed(:admin_issue, :set_issue_metadata, :set_confidentiality)
153
154        expect(permissions(assignee, confidential_issue_no_assignee)).to be_disallowed(:read_issue, :read_issue_iid, :update_issue, :admin_issue, :set_issue_metadata, :set_confidentiality)
155      end
156
157      it 'does not allow issue assignees to read or update confidential issue moved to an private project' do
158        confidential_issue.project = create(:project, :private)
159
160        expect(permissions(assignee, confidential_issue)).to be_disallowed(:read_issue, :read_issue_iid, :update_issue, :set_issue_metadata, :set_confidentiality)
161      end
162    end
163  end
164
165  context 'a public project' do
166    let(:project) { create(:project, :public) }
167    let(:issue) { create(:issue, project: project, assignees: [assignee], author: author) }
168    let(:issue_no_assignee) { create(:issue, project: project) }
169    let(:issue_locked) { create(:issue, :locked, project: project, author: author, assignees: [assignee]) }
170    let(:new_issue) { build(:issue, project: project) }
171
172    before do
173      project.add_guest(guest)
174      project.add_reporter(reporter)
175
176      group.add_reporter(reporter_from_group_link)
177
178      create(:project_group_link, group: group, project: project)
179    end
180
181    it 'does not allow anonymous user to create todos' do
182      expect(permissions(nil, issue)).to be_allowed(:read_issue)
183      expect(permissions(nil, issue)).to be_disallowed(:create_todo, :update_subscription, :set_issue_metadata, :set_confidentiality)
184      expect(permissions(nil, new_issue)).to be_disallowed(:create_issue, :set_issue_metadata, :set_confidentiality)
185    end
186
187    it 'allows guests to read issues' do
188      expect(permissions(guest, issue)).to be_allowed(:read_issue, :read_issue_iid, :create_todo, :update_subscription)
189      expect(permissions(guest, issue)).to be_disallowed(:update_issue, :admin_issue, :reopen_issue, :set_issue_metadata, :set_confidentiality)
190
191      expect(permissions(guest, issue_no_assignee)).to be_allowed(:read_issue, :read_issue_iid)
192      expect(permissions(guest, issue_no_assignee)).to be_disallowed(:update_issue, :admin_issue, :reopen_issue, :set_issue_metadata, :set_confidentiality)
193
194      expect(permissions(guest, issue_locked)).to be_allowed(:read_issue, :read_issue_iid)
195      expect(permissions(guest, issue_locked)).to be_disallowed(:update_issue, :admin_issue, :reopen_issue, :set_issue_metadata, :set_confidentiality)
196
197      expect(permissions(guest, new_issue)).to be_allowed(:create_issue, :set_issue_metadata, :set_confidentiality)
198    end
199
200    it 'allows reporters to read, update, reopen, and admin issues' do
201      expect(permissions(reporter, issue)).to be_allowed(:read_issue, :read_issue_iid, :update_issue, :admin_issue, :reopen_issue, :set_issue_metadata, :set_confidentiality)
202      expect(permissions(reporter, issue_no_assignee)).to be_allowed(:read_issue, :read_issue_iid, :update_issue, :admin_issue, :reopen_issue, :set_issue_metadata, :set_confidentiality)
203      expect(permissions(reporter, issue_locked)).to be_allowed(:read_issue, :read_issue_iid, :update_issue, :admin_issue, :set_issue_metadata, :set_confidentiality)
204      expect(permissions(reporter, issue_locked)).to be_disallowed(:reopen_issue)
205      expect(permissions(reporter, new_issue)).to be_allowed(:create_issue, :set_issue_metadata, :set_confidentiality)
206    end
207
208    it 'allows reporters from group links to read, update, reopen and admin issues' do
209      expect(permissions(reporter_from_group_link, issue)).to be_allowed(:read_issue, :read_issue_iid, :update_issue, :admin_issue, :reopen_issue, :set_issue_metadata, :set_confidentiality)
210      expect(permissions(reporter_from_group_link, issue_no_assignee)).to be_allowed(:read_issue, :read_issue_iid, :update_issue, :admin_issue, :reopen_issue, :set_issue_metadata, :set_confidentiality)
211      expect(permissions(reporter_from_group_link, issue_locked)).to be_allowed(:read_issue, :read_issue_iid, :update_issue, :admin_issue, :set_issue_metadata, :set_confidentiality)
212      expect(permissions(reporter_from_group_link, issue_locked)).to be_disallowed(:reopen_issue)
213      expect(permissions(reporter, new_issue)).to be_allowed(:create_issue, :set_issue_metadata, :set_confidentiality)
214    end
215
216    it 'allows issue authors to read, reopen and update their issues' do
217      expect(permissions(author, issue)).to be_allowed(:read_issue, :read_issue_iid, :update_issue, :reopen_issue)
218      expect(permissions(author, issue)).to be_disallowed(:admin_issue, :set_issue_metadata, :set_confidentiality)
219
220      expect(permissions(author, issue_no_assignee)).to be_allowed(:read_issue, :read_issue_iid)
221      expect(permissions(author, issue_no_assignee)).to be_disallowed(:update_issue, :admin_issue, :reopen_issue, :set_issue_metadata, :set_confidentiality)
222
223      expect(permissions(author, issue_locked)).to be_allowed(:read_issue, :read_issue_iid, :update_issue)
224      expect(permissions(author, issue_locked)).to be_disallowed(:admin_issue, :reopen_issue, :set_issue_metadata, :set_confidentiality)
225
226      expect(permissions(author, new_issue)).to be_allowed(:create_issue)
227      expect(permissions(author, new_issue)).to be_disallowed(:set_issue_metadata)
228    end
229
230    it 'allows issue assignees to read, reopen and update their issues' do
231      expect(permissions(assignee, issue)).to be_allowed(:read_issue, :read_issue_iid, :update_issue, :reopen_issue)
232      expect(permissions(assignee, issue)).to be_disallowed(:admin_issue, :set_issue_metadata, :set_confidentiality)
233
234      expect(permissions(assignee, issue_no_assignee)).to be_allowed(:read_issue, :read_issue_iid)
235      expect(permissions(assignee, issue_no_assignee)).to be_disallowed(:update_issue, :admin_issue, :reopen_issue, :set_issue_metadata, :set_confidentiality)
236
237      expect(permissions(assignee, issue_locked)).to be_allowed(:read_issue, :read_issue_iid, :update_issue)
238      expect(permissions(assignee, issue_locked)).to be_disallowed(:admin_issue, :reopen_issue, :set_issue_metadata, :set_confidentiality)
239    end
240
241    it 'allows non-members to read and create issues' do
242      expect(permissions(non_member, issue)).to be_allowed(:read_issue, :read_issue_iid)
243      expect(permissions(non_member, issue_no_assignee)).to be_allowed(:read_issue, :read_issue_iid)
244      expect(permissions(non_member, new_issue)).to be_allowed(:create_issue)
245    end
246
247    it 'allows non-members to read issues' do
248      expect(permissions(non_member, issue)).to be_allowed(:read_issue, :read_issue_iid)
249      expect(permissions(non_member, issue_no_assignee)).to be_allowed(:read_issue, :read_issue_iid)
250    end
251
252    it 'does not allow non-members to update, admin or set metadata except for set confidential flag' do
253      expect(permissions(non_member, issue)).to be_disallowed(:update_issue, :admin_issue, :set_issue_metadata, :set_confidentiality)
254      expect(permissions(non_member, issue_no_assignee)).to be_disallowed(:update_issue, :admin_issue, :set_issue_metadata, :set_confidentiality)
255      expect(permissions(non_member, new_issue)).to be_disallowed(:set_issue_metadata)
256      # this is allowed for non-members in a public project, as we want to let users report security issues
257      # see https://gitlab.com/gitlab-org/gitlab/-/issues/337665
258      expect(permissions(non_member, new_issue)).to be_allowed(:set_confidentiality)
259    end
260
261    it 'allows support_bot to read issues' do
262      # support_bot is still allowed read access in public projects through :public_access permission,
263      # see project_policy public_access rules policy (rule { can?(:public_access) }.policy {...})
264      expect(permissions(support_bot, issue)).to be_allowed(:read_issue, :read_issue_iid)
265      expect(permissions(support_bot, issue)).to be_disallowed(:update_issue, :admin_issue, :set_issue_metadata, :set_confidentiality)
266
267      expect(permissions(support_bot, issue_no_assignee)).to be_allowed(:read_issue, :read_issue_iid)
268      expect(permissions(support_bot, issue_no_assignee)).to be_disallowed(:update_issue, :admin_issue, :set_issue_metadata, :set_confidentiality)
269
270      expect(permissions(support_bot, new_issue)).to be_disallowed(:create_issue, :set_issue_metadata, :set_confidentiality)
271    end
272
273    it_behaves_like 'support bot with service desk enabled'
274
275    context 'when issues are private' do
276      before do
277        project.project_feature.update!(issues_access_level: ProjectFeature::PRIVATE)
278      end
279
280      let(:issue) { create(:issue, project: project, author: author) }
281      let(:visitor) { create(:user) }
282      let(:admin) { create(:user, :admin) }
283
284      it 'forbids visitors from viewing issues' do
285        expect(permissions(visitor, issue)).to be_disallowed(:read_issue)
286      end
287      it 'forbids visitors from commenting' do
288        expect(permissions(visitor, issue)).to be_disallowed(:create_note)
289      end
290      it 'forbids visitors from subscribing' do
291        expect(permissions(visitor, issue)).to be_disallowed(:update_subscription)
292      end
293      it 'allows guests to view' do
294        expect(permissions(guest, issue)).to be_allowed(:read_issue)
295      end
296      it 'allows guests to comment' do
297        expect(permissions(guest, issue)).to be_allowed(:create_note)
298      end
299      it 'allows guests to subscribe' do
300        expect(permissions(guest, issue)).to be_allowed(:update_subscription)
301      end
302
303      context 'when admin mode is enabled', :enable_admin_mode do
304        it 'allows admins to view' do
305          expect(permissions(admin, issue)).to be_allowed(:read_issue)
306        end
307
308        it 'allows admins to comment' do
309          expect(permissions(admin, issue)).to be_allowed(:create_note)
310        end
311      end
312
313      context 'when admin mode is disabled' do
314        it 'forbids admins to view' do
315          expect(permissions(admin, issue)).to be_disallowed(:read_issue)
316        end
317
318        it 'forbids admins to comment' do
319          expect(permissions(admin, issue)).to be_disallowed(:create_note)
320        end
321      end
322
323      it 'does not allow non-members to update or create issues' do
324        expect(permissions(non_member, issue)).to be_disallowed(:read_issue, :read_issue_iid, :update_issue, :admin_issue, :set_issue_metadata, :set_confidentiality)
325        expect(permissions(non_member, issue_no_assignee)).to be_disallowed(:update_issue, :admin_issue, :set_issue_metadata, :set_confidentiality)
326        expect(permissions(non_member, new_issue)).to be_disallowed(:create_issue, :set_issue_metadata, :set_confidentiality)
327      end
328
329      it_behaves_like 'support bot with service desk disabled'
330      it_behaves_like 'support bot with service desk enabled'
331    end
332
333    context 'with confidential issues' do
334      let(:confidential_issue) { create(:issue, :confidential, project: project, assignees: [assignee], author: author) }
335      let(:confidential_issue_no_assignee) { create(:issue, :confidential, project: project) }
336
337      it 'does not allow guests to read confidential issues' do
338        expect(permissions(guest, confidential_issue)).to be_disallowed(:read_issue, :read_issue_iid, :update_issue, :admin_issue)
339        expect(permissions(guest, confidential_issue_no_assignee)).to be_disallowed(:read_issue, :read_issue_iid, :update_issue, :admin_issue, :set_issue_metadata, :set_confidentiality)
340      end
341
342      it 'allows reporters to read, update, and admin confidential issues' do
343        expect(permissions(reporter, confidential_issue)).to be_allowed(:read_issue, :read_issue_iid, :update_issue, :admin_issue)
344        expect(permissions(reporter, confidential_issue_no_assignee)).to be_allowed(:read_issue, :read_issue_iid, :update_issue, :admin_issue, :set_issue_metadata, :set_confidentiality)
345      end
346
347      it 'allows reporter from group links to read, update, and admin confidential issues' do
348        expect(permissions(reporter_from_group_link, confidential_issue)).to be_allowed(:read_issue, :read_issue_iid, :update_issue, :admin_issue)
349        expect(permissions(reporter_from_group_link, confidential_issue_no_assignee)).to be_allowed(:read_issue, :read_issue_iid, :update_issue, :admin_issue, :set_issue_metadata, :set_confidentiality)
350      end
351
352      it 'allows issue authors to read and update their confidential issues' do
353        expect(permissions(author, confidential_issue)).to be_allowed(:read_issue, :read_issue_iid, :update_issue)
354        expect(permissions(author, confidential_issue)).to be_disallowed(:admin_issue, :set_issue_metadata, :set_confidentiality)
355
356        expect(permissions(author, confidential_issue_no_assignee)).to be_disallowed(:read_issue, :read_issue_iid, :update_issue, :admin_issue, :set_issue_metadata, :set_confidentiality)
357      end
358
359      it 'allows issue assignees to read and update their confidential issues' do
360        expect(permissions(assignee, confidential_issue)).to be_allowed(:read_issue, :read_issue_iid, :update_issue)
361        expect(permissions(assignee, confidential_issue)).to be_disallowed(:admin_issue, :set_issue_metadata, :set_confidentiality)
362
363        expect(permissions(assignee, confidential_issue_no_assignee)).to be_disallowed(:read_issue, :read_issue_iid, :update_issue, :admin_issue, :set_issue_metadata, :set_confidentiality)
364      end
365    end
366
367    context 'with a hidden issue' do
368      let(:user) { create(:user) }
369      let(:banned_user) { create(:user, :banned) }
370      let(:admin) { create(:user, :admin)}
371      let(:hidden_issue) { create(:issue, project: project, author: banned_user) }
372
373      it 'does not allow non-admin user to read the issue' do
374        expect(permissions(user, hidden_issue)).not_to be_allowed(:read_issue)
375      end
376
377      it 'allows admin to read the issue', :enable_admin_mode do
378        expect(permissions(admin, hidden_issue)).to be_allowed(:read_issue)
379      end
380    end
381  end
382
383  context 'with external authorization enabled' do
384    let(:user) { create(:user) }
385    let(:project) { create(:project, :public) }
386    let(:issue) { create(:issue, project: project) }
387    let(:policies) { described_class.new(user, issue) }
388
389    before do
390      enable_external_authorization_service_check
391    end
392
393    it 'can read the issue iid without accessing the external service' do
394      expect(::Gitlab::ExternalAuthorization).not_to receive(:access_allowed?)
395
396      expect(policies).to be_allowed(:read_issue_iid)
397    end
398  end
399end
400