project_policy_spec.rb 13.2 KB
Newer Older
1 2
require 'spec_helper'

3
describe ProjectPolicy do
4 5 6 7 8 9
  set(:guest) { create(:user) }
  set(:reporter) { create(:user) }
  set(:developer) { create(:user) }
  set(:master) { create(:user) }
  set(:owner) { create(:user) }
  set(:admin) { create(:admin) }
10
  let(:project) { create(:project, :public, namespace: owner.namespace) }
11

12
  let(:base_guest_permissions) do
D
Douwe Maan 已提交
13
    %i[
S
Sean McGivern 已提交
14 15 16
      read_project read_board read_list read_wiki read_issue
      read_project_for_iids read_issue_iid read_merge_request_iid read_label
      read_milestone read_project_snippet read_project_member read_note
17
      create_project create_issue create_note upload_file create_merge_request_in
18
      award_emoji
A
Alejandro Rodríguez 已提交
19
    ]
20 21
  end

22
  let(:base_reporter_permissions) do
D
Douwe Maan 已提交
23 24 25 26 27
    %i[
      download_code fork_project create_project_snippet update_issue
      admin_issue admin_label admin_list read_commit_status read_build
      read_container_image read_pipeline read_environment read_deployment
      read_merge_request download_wiki_code
A
Alejandro Rodríguez 已提交
28 29 30 31
    ]
  end

  let(:team_member_reporter_permissions) do
D
Douwe Maan 已提交
32
    %i[build_download_code build_read_container_image]
A
Alejandro Rodríguez 已提交
33 34 35
  end

  let(:developer_permissions) do
D
Douwe Maan 已提交
36
    %i[
37
      admin_milestone admin_merge_request update_merge_request create_commit_status
D
Douwe Maan 已提交
38
      update_commit_status create_build update_build create_pipeline
39
      update_pipeline create_merge_request_from create_wiki push_code
D
Douwe Maan 已提交
40 41
      resolve_note create_container_image update_container_image
      create_environment create_deployment
A
Alejandro Rodríguez 已提交
42 43 44
    ]
  end

45
  let(:base_master_permissions) do
D
Douwe Maan 已提交
46
    %i[
47
      push_to_delete_protected_branch update_project_snippet update_environment
48
      update_deployment admin_project_snippet
D
Douwe Maan 已提交
49 50 51
      admin_project_member admin_note admin_wiki admin_project
      admin_commit_status admin_build admin_container_image
      admin_pipeline admin_environment admin_deployment
A
Alejandro Rodríguez 已提交
52 53 54 55
    ]
  end

  let(:public_permissions) do
D
Douwe Maan 已提交
56 57 58 59
    %i[
      download_code fork_project read_commit_status read_pipeline
      read_container_image build_download_code build_read_container_image
      download_wiki_code
A
Alejandro Rodríguez 已提交
60 61 62 63
    ]
  end

  let(:owner_permissions) do
D
Douwe Maan 已提交
64 65 66
    %i[
      change_namespace change_visibility_level rename_project remove_project
      archive_project remove_fork_project destroy_merge_request destroy_issue
A
Alejandro Rodríguez 已提交
67
    ]
68 69
  end

70 71 72 73 74 75 76 77 78
  # Used in EE specs
  let(:additional_guest_permissions)  { [] }
  let(:additional_reporter_permissions) { [] }
  let(:additional_master_permissions) { [] }

  let(:guest_permissions) { base_guest_permissions + additional_guest_permissions }
  let(:reporter_permissions) { base_reporter_permissions + additional_reporter_permissions }
  let(:master_permissions) { base_master_permissions + additional_master_permissions }

79
  before do
80 81 82 83
    project.add_guest(guest)
    project.add_master(master)
    project.add_developer(developer)
    project.add_reporter(reporter)
84
  end
85

86 87 88 89 90 91 92 93
  def expect_allowed(*permissions)
    permissions.each { |p| is_expected.to be_allowed(p) }
  end

  def expect_disallowed(*permissions)
    permissions.each { |p| is_expected.not_to be_allowed(p) }
  end

94
  it 'does not include the read_issue permission when the issue author is not a member of the private project' do
95
    project = create(:project, :private)
96
    issue   = create(:issue, project: project, author: create(:user))
97 98
    user    = issue.author

99
    expect(project.team.member?(issue.author)).to be false
100

101
    expect(Ability).not_to be_allowed(user, :read_issue, project)
102
  end
A
Alejandro Rodríguez 已提交
103

104 105
  context 'when the feature is disabled' do
    subject { described_class.new(owner, project) }
106

107 108 109
    before do
      project.project_feature.update_attribute(:wiki_access_level, ProjectFeature::DISABLED)
    end
110

111 112 113
    it 'does not include the wiki permissions' do
      expect_disallowed :read_wiki, :create_wiki, :update_wiki, :admin_wiki, :download_wiki_code
    end
114 115
  end

116 117 118 119 120 121 122 123
  context 'issues feature' do
    subject { described_class.new(owner, project) }

    context 'when the feature is disabled' do
      it 'does not include the issues permissions' do
        project.issues_enabled = false
        project.save!

S
Sean McGivern 已提交
124
        expect_disallowed :read_issue, :read_issue_iid, :create_issue, :update_issue, :admin_issue
125 126 127 128 129 130 131 132 133 134
      end
    end

    context 'when the feature is disabled and external tracker configured' do
      it 'does not include the issues permissions' do
        create(:jira_service, project: project)

        project.issues_enabled = false
        project.save!

S
Sean McGivern 已提交
135
        expect_disallowed :read_issue, :read_issue_iid, :create_issue, :update_issue, :admin_issue
136 137 138 139
      end
    end
  end

140 141 142 143 144 145
  context 'merge requests feature' do
    subject { described_class.new(owner, project) }

    it 'disallows all permissions when the feature is disabled' do
      project.project_feature.update(merge_requests_access_level: ProjectFeature::DISABLED)

146
      mr_permissions = [:create_merge_request_from, :read_merge_request,
147
                        :update_merge_request, :admin_merge_request,
148
                        :create_merge_request_in]
149 150 151 152 153

      expect_disallowed(*mr_permissions)
    end
  end

154 155 156 157 158 159 160 161 162
  shared_examples 'archived project policies' do
    let(:feature_write_abilities) do
      described_class::READONLY_FEATURES_WHEN_ARCHIVED.flat_map do |feature|
        described_class.create_update_admin_destroy(feature)
      end
    end

    let(:other_write_abilities) do
      %i[
163 164
        create_merge_request_in
        create_merge_request_from
165 166 167 168 169
        push_to_delete_protected_branch
        push_code
        request_access
        upload_file
        resolve_note
170
        award_emoji
171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192
      ]
    end

    context 'when the project is archived' do
      before do
        project.archived = true
      end

      it 'disables write actions on all relevant project features' do
        expect_disallowed(*feature_write_abilities)
      end

      it 'disables some other important write actions' do
        expect_disallowed(*other_write_abilities)
      end

      it 'does not disable other other abilities' do
        expect_allowed(*(regular_abilities - feature_write_abilities - other_write_abilities))
      end
    end
  end

193 194 195 196 197
  shared_examples 'project policies as anonymous' do
    context 'abilities for public projects' do
      context 'when a project has pending invites' do
        let(:group) { create(:group, :public) }
        let(:project) { create(:project, :public, namespace: group) }
198
        let(:user_permissions) { [:create_merge_request_in, :create_project, :create_issue, :create_note, :upload_file, :award_emoji] }
199
        let(:anonymous_permissions) { guest_permissions - user_permissions  }
200

201
        subject { described_class.new(nil, project) }
202

203 204 205
        before do
          create(:group_member, :invited, group: group)
        end
206

207 208 209 210
        it 'does not grant owner access' do
          expect_allowed(*anonymous_permissions)
          expect_disallowed(*user_permissions)
        end
211 212 213 214

        it_behaves_like 'archived project policies' do
          let(:regular_abilities) { anonymous_permissions }
        end
215
      end
216 217
    end

218 219
    context 'abilities for non-public projects' do
      let(:project) { create(:project, namespace: owner.namespace) }
A
Alejandro Rodríguez 已提交
220

221
      subject { described_class.new(nil, project) }
A
Alejandro Rodríguez 已提交
222

223
      it { is_expected.to be_banned }
A
Alejandro Rodríguez 已提交
224
    end
225
  end
A
Alejandro Rodríguez 已提交
226

227 228
  shared_examples 'project policies as guest' do
    subject { described_class.new(guest, project) }
A
Alejandro Rodríguez 已提交
229

230 231
    context 'abilities for non-public projects' do
      let(:project) { create(:project, namespace: owner.namespace) }
Z
Z.J. van de Weg 已提交
232 233 234 235 236
      let(:reporter_public_build_permissions) do
        reporter_permissions - [:read_build, :read_pipeline]
      end

      it do
237 238 239 240 241 242
        expect_allowed(*guest_permissions)
        expect_disallowed(*reporter_public_build_permissions)
        expect_disallowed(*team_member_reporter_permissions)
        expect_disallowed(*developer_permissions)
        expect_disallowed(*master_permissions)
        expect_disallowed(*owner_permissions)
Z
Z.J. van de Weg 已提交
243
      end
244

245 246 247 248
      it_behaves_like 'archived project policies' do
        let(:regular_abilities) { guest_permissions }
      end

Z
Z.J. van de Weg 已提交
249
      context 'public builds enabled' do
250
        it do
251 252
          expect_allowed(*guest_permissions)
          expect_allowed(:read_build, :read_pipeline)
253 254 255
        end
      end

256
      context 'when public builds disabled' do
257
        before do
Z
Z.J. van de Weg 已提交
258
          project.update(public_builds: false)
259 260 261
        end

        it do
262 263
          expect_allowed(*guest_permissions)
          expect_disallowed(:read_build, :read_pipeline)
264
        end
A
Alejandro Rodríguez 已提交
265
      end
K
Kamil Trzcinski 已提交
266 267 268

      context 'when builds are disabled' do
        before do
269
          project.project_feature.update(builds_access_level: ProjectFeature::DISABLED)
K
Kamil Trzcinski 已提交
270 271 272
        end

        it do
273 274
          expect_disallowed(:read_build)
          expect_allowed(:read_pipeline)
K
Kamil Trzcinski 已提交
275 276
        end
      end
A
Alejandro Rodríguez 已提交
277
    end
278 279 280 281 282
  end

  shared_examples 'project policies as reporter' do
    context 'abilities for non-public projects' do
      let(:project) { create(:project, namespace: owner.namespace) }
A
Alejandro Rodríguez 已提交
283

284
      subject { described_class.new(reporter, project) }
A
Alejandro Rodríguez 已提交
285 286

      it do
287 288 289 290 291 292
        expect_allowed(*guest_permissions)
        expect_allowed(*reporter_permissions)
        expect_allowed(*team_member_reporter_permissions)
        expect_disallowed(*developer_permissions)
        expect_disallowed(*master_permissions)
        expect_disallowed(*owner_permissions)
A
Alejandro Rodríguez 已提交
293
      end
294 295 296 297

      it_behaves_like 'archived project policies' do
        let(:regular_abilities) { reporter_permissions }
      end
A
Alejandro Rodríguez 已提交
298
    end
299
  end
A
Alejandro Rodríguez 已提交
300

301 302 303 304 305
  shared_examples 'project policies as developer' do
    context 'abilities for non-public projects' do
      let(:project) { create(:project, namespace: owner.namespace) }

      subject { described_class.new(developer, project) }
A
Alejandro Rodríguez 已提交
306 307

      it do
308 309 310 311 312 313
        expect_allowed(*guest_permissions)
        expect_allowed(*reporter_permissions)
        expect_allowed(*team_member_reporter_permissions)
        expect_allowed(*developer_permissions)
        expect_disallowed(*master_permissions)
        expect_disallowed(*owner_permissions)
A
Alejandro Rodríguez 已提交
314
      end
315 316 317 318

      it_behaves_like 'archived project policies' do
        let(:regular_abilities) { developer_permissions }
      end
A
Alejandro Rodríguez 已提交
319
    end
320 321 322 323 324
  end

  shared_examples 'project policies as master' do
    context 'abilities for non-public projects' do
      let(:project) { create(:project, namespace: owner.namespace) }
A
Alejandro Rodríguez 已提交
325

326
      subject { described_class.new(master, project) }
A
Alejandro Rodríguez 已提交
327 328

      it do
329 330 331 332 333 334
        expect_allowed(*guest_permissions)
        expect_allowed(*reporter_permissions)
        expect_allowed(*team_member_reporter_permissions)
        expect_allowed(*developer_permissions)
        expect_allowed(*master_permissions)
        expect_disallowed(*owner_permissions)
A
Alejandro Rodríguez 已提交
335
      end
336 337 338 339

      it_behaves_like 'archived project policies' do
        let(:regular_abilities) { master_permissions }
      end
A
Alejandro Rodríguez 已提交
340
    end
341 342 343 344 345
  end

  shared_examples 'project policies as owner' do
    context 'abilities for non-public projects' do
      let(:project) { create(:project, namespace: owner.namespace) }
A
Alejandro Rodríguez 已提交
346

347
      subject { described_class.new(owner, project) }
A
Alejandro Rodríguez 已提交
348

349
      it do
350 351 352 353 354 355
        expect_allowed(*guest_permissions)
        expect_allowed(*reporter_permissions)
        expect_allowed(*team_member_reporter_permissions)
        expect_allowed(*developer_permissions)
        expect_allowed(*master_permissions)
        expect_allowed(*owner_permissions)
356
      end
357 358 359 360

      it_behaves_like 'archived project policies' do
        let(:regular_abilities) { owner_permissions }
      end
361
    end
362
  end
363

364 365 366 367 368
  shared_examples 'project policies as admin' do
    context 'abilities for non-public projects' do
      let(:project) { create(:project, namespace: owner.namespace) }

      subject { described_class.new(admin, project) }
369

A
Alejandro Rodríguez 已提交
370
      it do
371 372 373 374 375 376
        expect_allowed(*guest_permissions)
        expect_allowed(*reporter_permissions)
        expect_disallowed(*team_member_reporter_permissions)
        expect_allowed(*developer_permissions)
        expect_allowed(*master_permissions)
        expect_allowed(*owner_permissions)
A
Alejandro Rodríguez 已提交
377
      end
378 379 380 381

      it_behaves_like 'archived project policies' do
        let(:regular_abilities) { owner_permissions }
      end
A
Alejandro Rodríguez 已提交
382 383
    end
  end
384 385 386 387 388 389 390 391

  it_behaves_like 'project policies as anonymous'
  it_behaves_like 'project policies as guest'
  it_behaves_like 'project policies as reporter'
  it_behaves_like 'project policies as developer'
  it_behaves_like 'project policies as master'
  it_behaves_like 'project policies as owner'
  it_behaves_like 'project policies as admin'
392 393 394 395 396 397 398 399 400 401 402

  context 'when a public project has merge requests allowing access' do
    include ProjectForksHelper
    let(:user) { create(:user) }
    let(:target_project) { create(:project, :public) }
    let(:project) { fork_project(target_project) }
    let!(:merge_request) do
      create(
        :merge_request,
        target_project: target_project,
        source_project: project,
403
        allow_collaboration: true
404 405 406
      )
    end
    let(:maintainer_abilities) do
407
      %w(create_build create_pipeline)
408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428
    end

    subject { described_class.new(user, project) }

    it 'does not allow pushing code' do
      expect_disallowed(*maintainer_abilities)
    end

    it 'allows pushing if the user is a member with push access to the target project' do
      target_project.add_developer(user)

      expect_allowed(*maintainer_abilities)
    end

    it 'dissallows abilities to a maintainer if the merge request was closed' do
      target_project.add_developer(user)
      merge_request.close!

      expect_disallowed(*maintainer_abilities)
    end
  end
429
end