Cancel all running CI jobs when user is blocked
This prevents a MITM attack where attacker could still access Git repository if any jobs were running long enough.
This commit is contained in:
parent
58290d90e5
commit
c9396f31c6
5 changed files with 68 additions and 1 deletions
|
@ -267,6 +267,16 @@ class User < ApplicationRecord
|
|||
BLOCKED_MESSAGE
|
||||
end
|
||||
end
|
||||
|
||||
# rubocop: disable CodeReuse/ServiceClass
|
||||
# Ideally we should not call a service object here but user.block
|
||||
# is also bcalled by Users::MigrateToGhostUserService which references
|
||||
# this state transition object in order to do a rollback.
|
||||
# For this reason the tradeoff is to disable this cop.
|
||||
after_transition any => :blocked do |user|
|
||||
Ci::CancelUserPipelinesService.new.execute(user)
|
||||
end
|
||||
# rubocop: enable CodeReuse/ServiceClass
|
||||
end
|
||||
|
||||
# Scopes
|
||||
|
|
13
app/services/ci/cancel_user_pipelines_service.rb
Normal file
13
app/services/ci/cancel_user_pipelines_service.rb
Normal file
|
@ -0,0 +1,13 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Ci
|
||||
class CancelUserPipelinesService
|
||||
# rubocop: disable CodeReuse/ActiveRecord
|
||||
# This is a bug with CodeReuse/ActiveRecord cop
|
||||
# https://gitlab.com/gitlab-org/gitlab/issues/32332
|
||||
def execute(user)
|
||||
user.pipelines.cancelable.find_each(&:cancel_running)
|
||||
end
|
||||
# rubocop: enable CodeReuse/ActiveRecord
|
||||
end
|
||||
end
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Cancel all running CI jobs triggered by the user who is just blocked
|
||||
merge_request:
|
||||
author:
|
||||
type: security
|
|
@ -1097,11 +1097,27 @@ describe User do
|
|||
describe 'blocking user' do
|
||||
let(:user) { create(:user, name: 'John Smith') }
|
||||
|
||||
it "blocks user" do
|
||||
it 'blocks user' do
|
||||
user.block
|
||||
|
||||
expect(user.blocked?).to be_truthy
|
||||
end
|
||||
|
||||
context 'when user has running CI pipelines' do
|
||||
let(:service) { double }
|
||||
|
||||
before do
|
||||
pipeline = create(:ci_pipeline, :running, user: user)
|
||||
create(:ci_build, :running, pipeline: pipeline)
|
||||
end
|
||||
|
||||
it 'cancels all running pipelines and related jobs' do
|
||||
expect(Ci::CancelUserPipelinesService).to receive(:new).and_return(service)
|
||||
expect(service).to receive(:execute).with(user)
|
||||
|
||||
user.block
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '.filter_items' do
|
||||
|
|
23
spec/services/ci/cancel_user_pipelines_service_spec.rb
Normal file
23
spec/services/ci/cancel_user_pipelines_service_spec.rb
Normal file
|
@ -0,0 +1,23 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
describe Ci::CancelUserPipelinesService do
|
||||
describe '#execute' do
|
||||
let(:user) { create(:user) }
|
||||
|
||||
subject { described_class.new.execute(user) }
|
||||
|
||||
context 'when user has running CI pipelines' do
|
||||
let(:pipeline) { create(:ci_pipeline, :running, user: user) }
|
||||
let!(:build) { create(:ci_build, :running, pipeline: pipeline) }
|
||||
|
||||
it 'cancels all running pipelines and related jobs' do
|
||||
subject
|
||||
|
||||
expect(pipeline.reload).to be_canceled
|
||||
expect(build.reload).to be_canceled
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in a new issue