Commit 3f856b60 authored by Fabio Pitino's avatar Fabio Pitino

Prevent creating pipeline on free and trial plans without CC info

Return an error if user is not validated via add credit card info and
tries to create a pipeline on Free or trial plan.
parent 6cadce10
......@@ -10,6 +10,7 @@ module Enums
unknown_failure: 0,
config_error: 1,
external_validation_failure: 2,
user_not_verified: 3,
activity_limit_exceeded: 20,
size_limit_exceeded: 21,
job_activity_limit_exceeded: 22,
......
......@@ -11,6 +11,7 @@ module Ci
{ unknown_failure: 'The reason for the pipeline failure is unknown.',
config_error: 'The pipeline failed due to an error on the CI/CD configuration file.',
external_validation_failure: 'The external pipeline validation failed.',
user_not_verified: 'The pipeline failed due to the user not being verified',
activity_limit_exceeded: 'The pipeline activity limit was exceeded.',
size_limit_exceeded: 'The pipeline size limit was exceeded.',
job_activity_limit_exceeded: 'The pipeline job activity limit was exceeded.',
......
---
name: ci_require_credit_card_on_free_plan
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/61152
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/330104
milestone: '13.12'
type: development
group: group::continuous integration
default_enabled: false
---
name: ci_require_credit_card_on_trial_plan
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/61152
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/330105
milestone: '13.12'
type: development
group: group::continuous integration
default_enabled: false
......@@ -396,6 +396,27 @@ module EE
!password_automatically_set?
end
def has_valid_credit_card?
credit_card_validated_at.present?
end
def requires_credit_card_to_run_pipelines?(project)
return false unless ::Gitlab.com?
root_namespace = project.root_namespace
if root_namespace.free_plan?
::Feature.enabled?(:ci_require_credit_card_on_free_plan, project, default_enabled: :yaml)
elsif root_namespace.trial?
::Feature.enabled?(:ci_require_credit_card_on_trial_plan, project, default_enabled: :yaml)
else
false
end
end
def has_required_credit_card_to_run_pipelines?(project)
has_valid_credit_card? || !requires_credit_card_to_run_pipelines?(project)
end
protected
override :password_required?
......
......@@ -18,6 +18,10 @@ module EE
return error('Pipeline is disabled for mirror updates')
end
if current_user && !current_user.has_required_credit_card_to_run_pipelines?(project)
return error('Credit card required to be on file in order to create a pipeline', drop_reason: :user_not_verified)
end
super
end
end
......
......@@ -19,10 +19,12 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Validate::Abilities do
let(:ref) { 'master' }
describe '#perform!' do
before do
project.add_developer(user)
end
context 'when triggering builds for project mirrors is disabled' do
it 'returns an error' do
project.add_developer(user)
allow(command)
.to receive(:allow_mirror_update)
.and_return(true)
......@@ -37,5 +39,40 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Validate::Abilities do
.to include('Pipeline is disabled for mirror updates')
end
end
describe 'credit card requirement' do
context 'when user does not have credit card for pipelines in project' do
before do
allow(user)
.to receive(:has_required_credit_card_to_run_pipelines?)
.with(project)
.and_return(false)
end
it 'breaks the chain with an error' do
step.perform!
expect(step.break?).to be_truthy
expect(pipeline.errors.to_a)
.to include('Credit card required to be on file in order to create a pipeline')
end
end
context 'when user has credit card for pipelines in project' do
before do
allow(user)
.to receive(:has_required_credit_card_to_run_pipelines?)
.with(project)
.and_return(true)
end
it 'succeeds the step' do
step.perform!
expect(step.break?).to be_falsey
expect(pipeline.errors).to be_empty
end
end
end
end
end
......@@ -1674,4 +1674,41 @@ RSpec.describe User do
end
end
end
describe '#has_required_credit_card_to_run_pipelines?' do
let_it_be(:project) { create(:project) }
subject { user.has_required_credit_card_to_run_pipelines?(project) }
using RSpec::Parameterized::TableSyntax
where(:is_saas, :cc_present, :is_free, :is_trial, :free_ff_enabled, :trial_ff_enabled, :result) do
# self-hosted
false | false | false | false | true | true | true # paid plan
false | false | false | true | true | true | true # missing CC on trial plan
# saas
true | false | false | false | true | true | true # missing CC on paid plan
true | false | true | false | true | true | false # missing CC on free plan
true | false | true | false | false | true | true # missing CC on free plan - FF off
true | false | false | true | true | true | false # missing CC on trial plan
true | false | false | true | true | false | true # missing CC on trial plan - FF off
true | true | true | false | true | true | true # present CC on free plan
true | true | false | true | true | true | true # present CC on trial plan
end
with_them do
before do
allow(::Gitlab).to receive(:com?).and_return(is_saas)
allow(user).to receive(:credit_card_validated_at).and_return(Time.current) if cc_present
allow(project.namespace).to receive(:free_plan?).and_return(is_free)
allow(project.namespace).to receive(:trial?).and_return(is_trial)
stub_feature_flags(
ci_require_credit_card_on_free_plan: free_ff_enabled,
ci_require_credit_card_on_trial_plan: trial_ff_enabled)
end
it { is_expected.to eq(result) }
end
end
end
......@@ -173,6 +173,54 @@ RSpec.describe Ci::CreatePipelineService, '#execute' do
end
end
describe 'credit card requirement' do
shared_examples 'creates a successful pipeline' do
it 'creates a successful pipeline' do
pipeline = create_pipeline!
expect(pipeline).to be_created_successfully
end
end
context 'when credit card is required' do
context 'when project is on free plan' do
before do
allow(::Gitlab).to receive(:com?).and_return(true)
namespace.gitlab_subscription.update!(hosted_plan: create(:free_plan))
end
context 'when user has credit card' do
before do
allow(user).to receive(:credit_card_validated_at).and_return(Time.current)
end
it_behaves_like 'creates a successful pipeline'
end
context 'when user does not have credit card' do
it 'creates a pipeline with errors', :aggregate_failures do
pipeline = create_pipeline!
expect(pipeline).not_to be_created_successfully
expect(pipeline.failure_reason).to eq('user_not_verified')
end
context 'when feature flag is disabled' do
before do
stub_feature_flags(ci_require_credit_card_on_free_plan: false)
end
it_behaves_like 'creates a successful pipeline'
end
end
end
end
context 'when credit card is not required' do
it_behaves_like 'creates a successful pipeline'
end
end
def create_pipeline!
service.execute(:push)
end
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment