Welcome to mirror list, hosted at ThFree Co, Russian Federation.

revoke_service_spec.rb « resource_access_tokens « services « spec - gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 8f89696cc55b97c58e6b31c80b8e218c58925fd2 (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
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
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe ResourceAccessTokens::RevokeService do
  subject { described_class.new(user, resource, access_token).execute }

  let_it_be(:user) { create(:user) }
  let_it_be(:user_non_priviledged) { create(:user) }
  let_it_be(:resource_bot) { create(:user, :project_bot) }

  let(:access_token) { create(:personal_access_token, user: resource_bot) }

  describe '#execute', :sidekiq_inline do
    shared_examples 'revokes access token' do
      it { expect(subject.success?).to be true }

      it { expect(subject.message).to eq("Access token #{access_token.name} has been revoked and the bot user has been scheduled for deletion.") }

      it 'calls delete user worker' do
        expect(DeleteUserWorker).to receive(:perform_async).with(user.id, resource_bot.id, skip_authorization: true)

        subject
      end

      it 'removes membership of bot user' do
        subject

        expect(resource.reload.users).not_to include(resource_bot)
      end

      context 'when user_destroy_with_limited_execution_time_worker is enabled' do
        it 'initiates user removal' do
          subject

          expect(
            Users::GhostUserMigration.where(user: resource_bot,
                                            initiator_user: user)
          ).to be_exists
        end
      end

      context 'when user_destroy_with_limited_execution_time_worker is disabled' do
        before do
          stub_feature_flags(user_destroy_with_limited_execution_time_worker: false)
        end

        it 'transfer issuables of bot user to ghost user' do
          issue = create(:issue, author: resource_bot)

          subject

          expect(issue.reload.author.ghost?).to be true
        end

        it 'deletes project bot user' do
          subject

          expect(User.exists?(resource_bot.id)).to be_falsy
        end
      end

      it 'logs the event' do
        allow(Gitlab::AppLogger).to receive(:info)

        subject

        expect(Gitlab::AppLogger).to have_received(:info).with("PROJECT ACCESS TOKEN REVOCATION: revoked_by: #{user.username}, project_id: #{resource.id}, token_user: #{resource_bot.name}, token_id: #{access_token.id}")
      end
    end

    shared_examples 'rollback revoke steps' do
      it 'does not revoke the access token' do
        subject

        expect(access_token.reload.revoked?).to be false
      end

      it 'does not remove bot from member list' do
        subject

        expect(resource.reload.users).to include(resource_bot)
      end

      it 'does not transfer issuables of bot user to ghost user' do
        issue = create(:issue, author: resource_bot)

        subject

        expect(issue.reload.author.ghost?).to be false
      end

      it 'does not destroy project bot user' do
        subject

        expect(User.exists?(resource_bot.id)).to be_truthy
      end
    end

    shared_examples 'revoke fails' do |resource_type|
      let_it_be(:other_user) { create(:user) }

      context "when access token does not belong to this #{resource_type}" do
        it 'does not find the bot' do
          other_access_token = create(:personal_access_token, user: other_user)

          response = described_class.new(user, resource, other_access_token).execute

          expect(response.success?).to be false
          expect(response.message).to eq("Failed to find bot user")
          expect(access_token.reload.revoked?).to be false
        end
      end

      context 'when user does not have permission to destroy bot' do
        context "when non-#{resource_type} member tries to delete project bot" do
          it 'does not allow other user to delete bot' do
            response = described_class.new(other_user, resource, access_token).execute

            expect(response.success?).to be false
            expect(response.message).to eq("#{other_user.name} cannot delete #{access_token.user.name}")
            expect(access_token.reload.revoked?).to be false
          end
        end

        context "when non-priviledged #{resource_type} member tries to delete project bot" do
          it 'does not allow developer to delete bot' do
            response = described_class.new(user_non_priviledged, resource, access_token).execute

            expect(response.success?).to be false
            expect(response.message).to eq("#{user_non_priviledged.name} cannot delete #{access_token.user.name}")
            expect(access_token.reload.revoked?).to be false
          end
        end
      end

      context 'when deletion of bot user fails' do
        before do
          allow_next_instance_of(::ResourceAccessTokens::RevokeService) do |service|
            allow(service).to receive(:execute).and_return(false)
          end
        end

        it_behaves_like 'rollback revoke steps'
      end
    end

    context 'when resource is a project' do
      let_it_be(:resource) { create(:project, :private) }

      before do
        resource.add_maintainer(user)
        resource.add_developer(user_non_priviledged)
        resource.add_maintainer(resource_bot)
      end

      it_behaves_like 'revokes access token'

      it_behaves_like 'revoke fails', 'project'
    end

    context 'when resource is a group' do
      let_it_be(:resource) { create(:group, :private) }

      before do
        resource.add_owner(user)
        resource.add_maintainer(user_non_priviledged)
        resource.add_maintainer(resource_bot)
      end

      it_behaves_like 'revokes access token'

      it_behaves_like 'revoke fails', 'group'
    end
  end
end