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

3
describe ProjectPolicy do
4 5 6
  set(:guest) { create(:user) }
  set(:reporter) { create(:user) }
  set(:developer) { create(:user) }
7
  set(:maintainer) { create(:user) }
8 9
  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_maintainer_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
67
      set_issue_iid set_issue_created_at set_note_created_at
A
Alejandro Rodríguez 已提交
68
    ]
69 70
  end

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

  let(:guest_permissions) { base_guest_permissions + additional_guest_permissions }
  let(:reporter_permissions) { base_reporter_permissions + additional_reporter_permissions }
78
  let(:maintainer_permissions) { base_maintainer_permissions + additional_maintainer_permissions }
79

80
  before do
81
    project.add_guest(guest)
82
    project.add_maintainer(maintainer)
83 84
    project.add_developer(developer)
    project.add_reporter(reporter)
85
  end
86

87 88 89 90 91 92 93 94
  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

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

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

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

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

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

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

117 118 119 120 121 122 123 124
  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 已提交
125
        expect_disallowed :read_issue, :read_issue_iid, :create_issue, :update_issue, :admin_issue
126 127 128 129 130 131 132 133 134 135
      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 已提交
136
        expect_disallowed :read_issue, :read_issue_iid, :create_issue, :update_issue, :admin_issue
137 138 139 140
      end
    end
  end

141 142 143 144 145 146
  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)

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

      expect_disallowed(*mr_permissions)
    end
  end

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
  context 'builds feature' do
    subject { described_class.new(owner, project) }

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

      builds_permissions = [
        :create_pipeline, :update_pipeline, :admin_pipeline, :destroy_pipeline,
        :create_build, :read_build, :update_build, :admin_build, :destroy_build,
        :create_pipeline_schedule, :read_pipeline_schedule, :update_pipeline_schedule, :admin_pipeline_schedule, :destroy_pipeline_schedule,
        :create_environment, :read_environment, :update_environment, :admin_environment, :destroy_environment,
        :create_cluster, :read_cluster, :update_cluster, :admin_cluster, :destroy_cluster,
        :create_deployment, :read_deployment, :update_deployment, :admin_deployment, :destroy_deployment
      ]

      expect_disallowed(*builds_permissions)
    end
  end

  context 'repository feature' do
    subject { described_class.new(owner, project) }

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

      repository_permissions = [
        :create_pipeline, :update_pipeline, :admin_pipeline, :destroy_pipeline,
        :create_build, :read_build, :update_build, :admin_build, :destroy_build,
        :create_pipeline_schedule, :read_pipeline_schedule, :update_pipeline_schedule, :admin_pipeline_schedule, :destroy_pipeline_schedule,
        :create_environment, :read_environment, :update_environment, :admin_environment, :destroy_environment,
        :create_cluster, :read_cluster, :update_cluster, :admin_cluster, :destroy_cluster,
        :create_deployment, :read_deployment, :update_deployment, :admin_deployment, :destroy_deployment
      ]

      expect_disallowed(*repository_permissions)
    end
  end

193 194 195 196 197 198 199 200 201
  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[
202 203
        create_merge_request_in
        create_merge_request_from
204 205 206 207 208
        push_to_delete_protected_branch
        push_code
        request_access
        upload_file
        resolve_note
209
        award_emoji
210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231
      ]
    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

232 233 234 235 236
  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) }
237
        let(:user_permissions) { [:create_merge_request_in, :create_project, :create_issue, :create_note, :upload_file, :award_emoji] }
238
        let(:anonymous_permissions) { guest_permissions - user_permissions  }
239

240
        subject { described_class.new(nil, project) }
241

242 243 244
        before do
          create(:group_member, :invited, group: group)
        end
245

246 247 248 249
        it 'does not grant owner access' do
          expect_allowed(*anonymous_permissions)
          expect_disallowed(*user_permissions)
        end
250 251 252 253

        it_behaves_like 'archived project policies' do
          let(:regular_abilities) { anonymous_permissions }
        end
254
      end
255 256
    end

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

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

262
      it { is_expected.to be_banned }
A
Alejandro Rodríguez 已提交
263
    end
264
  end
A
Alejandro Rodríguez 已提交
265

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

269 270
    context 'abilities for non-public projects' do
      let(:project) { create(:project, namespace: owner.namespace) }
Z
Z.J. van de Weg 已提交
271 272 273 274 275
      let(:reporter_public_build_permissions) do
        reporter_permissions - [:read_build, :read_pipeline]
      end

      it do
276 277 278 279
        expect_allowed(*guest_permissions)
        expect_disallowed(*reporter_public_build_permissions)
        expect_disallowed(*team_member_reporter_permissions)
        expect_disallowed(*developer_permissions)
280
        expect_disallowed(*maintainer_permissions)
281
        expect_disallowed(*owner_permissions)
Z
Z.J. van de Weg 已提交
282
      end
283

284 285 286 287
      it_behaves_like 'archived project policies' do
        let(:regular_abilities) { guest_permissions }
      end

Z
Z.J. van de Weg 已提交
288
      context 'public builds enabled' do
289
        it do
290 291
          expect_allowed(*guest_permissions)
          expect_allowed(:read_build, :read_pipeline)
292 293 294
        end
      end

295
      context 'when public builds disabled' do
296
        before do
Z
Z.J. van de Weg 已提交
297
          project.update(public_builds: false)
298 299 300
        end

        it do
301 302
          expect_allowed(*guest_permissions)
          expect_disallowed(:read_build, :read_pipeline)
303
        end
A
Alejandro Rodríguez 已提交
304
      end
K
Kamil Trzcinski 已提交
305 306 307

      context 'when builds are disabled' do
        before do
308
          project.project_feature.update(builds_access_level: ProjectFeature::DISABLED)
K
Kamil Trzcinski 已提交
309 310 311
        end

        it do
312 313
          expect_disallowed(:read_build)
          expect_allowed(:read_pipeline)
K
Kamil Trzcinski 已提交
314 315
        end
      end
A
Alejandro Rodríguez 已提交
316
    end
317 318 319 320 321
  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 已提交
322

323
      subject { described_class.new(reporter, project) }
A
Alejandro Rodríguez 已提交
324 325

      it do
326 327 328 329
        expect_allowed(*guest_permissions)
        expect_allowed(*reporter_permissions)
        expect_allowed(*team_member_reporter_permissions)
        expect_disallowed(*developer_permissions)
330
        expect_disallowed(*maintainer_permissions)
331
        expect_disallowed(*owner_permissions)
A
Alejandro Rodríguez 已提交
332
      end
333 334 335 336

      it_behaves_like 'archived project policies' do
        let(:regular_abilities) { reporter_permissions }
      end
A
Alejandro Rodríguez 已提交
337
    end
338
  end
A
Alejandro Rodríguez 已提交
339

340 341 342 343 344
  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 已提交
345 346

      it do
347 348 349 350
        expect_allowed(*guest_permissions)
        expect_allowed(*reporter_permissions)
        expect_allowed(*team_member_reporter_permissions)
        expect_allowed(*developer_permissions)
351
        expect_disallowed(*maintainer_permissions)
352
        expect_disallowed(*owner_permissions)
A
Alejandro Rodríguez 已提交
353
      end
354 355 356 357

      it_behaves_like 'archived project policies' do
        let(:regular_abilities) { developer_permissions }
      end
A
Alejandro Rodríguez 已提交
358
    end
359 360
  end

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

365
      subject { described_class.new(maintainer, project) }
A
Alejandro Rodríguez 已提交
366 367

      it do
368 369 370 371
        expect_allowed(*guest_permissions)
        expect_allowed(*reporter_permissions)
        expect_allowed(*team_member_reporter_permissions)
        expect_allowed(*developer_permissions)
372
        expect_allowed(*maintainer_permissions)
373
        expect_disallowed(*owner_permissions)
A
Alejandro Rodríguez 已提交
374
      end
375 376

      it_behaves_like 'archived project policies' do
377
        let(:regular_abilities) { maintainer_permissions }
378
      end
A
Alejandro Rodríguez 已提交
379
    end
380 381 382 383 384
  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 已提交
385

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

388
      it do
389 390 391 392
        expect_allowed(*guest_permissions)
        expect_allowed(*reporter_permissions)
        expect_allowed(*team_member_reporter_permissions)
        expect_allowed(*developer_permissions)
393
        expect_allowed(*maintainer_permissions)
394
        expect_allowed(*owner_permissions)
395
      end
396 397 398 399

      it_behaves_like 'archived project policies' do
        let(:regular_abilities) { owner_permissions }
      end
400
    end
401
  end
402

403 404 405 406 407
  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) }
408

A
Alejandro Rodríguez 已提交
409
      it do
410 411 412 413
        expect_allowed(*guest_permissions)
        expect_allowed(*reporter_permissions)
        expect_disallowed(*team_member_reporter_permissions)
        expect_allowed(*developer_permissions)
414
        expect_allowed(*maintainer_permissions)
415
        expect_allowed(*owner_permissions)
A
Alejandro Rodríguez 已提交
416
      end
417 418 419 420

      it_behaves_like 'archived project policies' do
        let(:regular_abilities) { owner_permissions }
      end
A
Alejandro Rodríguez 已提交
421 422
    end
  end
423 424 425 426 427

  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'
428
  it_behaves_like 'project policies as maintainer'
429 430
  it_behaves_like 'project policies as owner'
  it_behaves_like 'project policies as admin'
431 432 433 434 435 436 437 438 439 440 441

  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,
442
        allow_collaboration: true
443 444 445
      )
    end
    let(:maintainer_abilities) do
446
      %w(create_build create_pipeline)
447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467
    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
468
end