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:
Fabio Pitino 2019-09-13 07:40:00 +01:00 committed by Yorick Peterse
parent 58290d90e5
commit c9396f31c6
No known key found for this signature in database
GPG key ID: EDD30D2BEB691AC9
5 changed files with 68 additions and 1 deletions

View file

@ -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

View 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

View file

@ -0,0 +1,5 @@
---
title: Cancel all running CI jobs triggered by the user who is just blocked
merge_request:
author:
type: security

View file

@ -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

View 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