Commit fc7a89c4 authored by Aishwarya Subramanian's avatar Aishwarya Subramanian

Introduce Project bot users

Adds a new type of users - Project bot users.
The purpose of these users is that they will be
used internally to generate project level access token.
We also define the policy for this user based on
it's purpose.
parent 9048b675
...@@ -337,7 +337,8 @@ class User < ApplicationRecord ...@@ -337,7 +337,8 @@ class User < ApplicationRecord
scope :with_dashboard, -> (dashboard) { where(dashboard: dashboard) } scope :with_dashboard, -> (dashboard) { where(dashboard: dashboard) }
scope :with_public_profile, -> { where(private_profile: false) } scope :with_public_profile, -> { where(private_profile: false) }
scope :bots, -> { where(user_type: UserTypeEnums.bots.values) } scope :bots, -> { where(user_type: UserTypeEnums.bots.values) }
scope :not_bots, -> { humans.or(where.not(user_type: UserTypeEnums.bots.values)) } scope :bots_without_project_bot, -> { bots.where.not(user_type: UserTypeEnums.bots[:project_bot]) }
scope :with_project_bots, -> { humans.or(where.not(user_type: UserTypeEnums.bots.except(:project_bot).values)) }
scope :humans, -> { where(user_type: nil) } scope :humans, -> { where(user_type: nil) }
scope :with_expiring_and_not_notified_personal_access_tokens, ->(at) do scope :with_expiring_and_not_notified_personal_access_tokens, ->(at) do
...@@ -657,8 +658,10 @@ class User < ApplicationRecord ...@@ -657,8 +658,10 @@ class User < ApplicationRecord
UserTypeEnums.bots.has_key?(user_type) UserTypeEnums.bots.has_key?(user_type)
end end
# The explicit check for project_bot will be removed with Bot Categorization
# Ref: https://gitlab.com/gitlab-org/gitlab/-/issues/213945
def internal? def internal?
ghost? || bot? ghost? || (bot? && !project_bot?)
end end
# We are transitioning from ghost boolean column to user_type # We are transitioning from ghost boolean column to user_type
...@@ -668,12 +671,16 @@ class User < ApplicationRecord ...@@ -668,12 +671,16 @@ class User < ApplicationRecord
ghost ghost
end end
# The explicit check for project_bot will be removed with Bot Categorization
# Ref: https://gitlab.com/gitlab-org/gitlab/-/issues/213945
def self.internal def self.internal
where(ghost: true).or(bots) where(ghost: true).or(bots_without_project_bot)
end end
# The explicit check for project_bot will be removed with Bot Categorization
# Ref: https://gitlab.com/gitlab-org/gitlab/-/issues/213945
def self.non_internal def self.non_internal
without_ghosts.not_bots without_ghosts.with_project_bots
end end
# #
......
...@@ -6,7 +6,7 @@ module UserTypeEnums ...@@ -6,7 +6,7 @@ module UserTypeEnums
end end
def self.bots def self.bots
@bots ||= { alert_bot: 2 }.with_indifferent_access @bots ||= { alert_bot: 2, project_bot: 6 }.with_indifferent_access
end end
end end
......
...@@ -17,6 +17,8 @@ class GlobalPolicy < BasePolicy ...@@ -17,6 +17,8 @@ class GlobalPolicy < BasePolicy
condition(:private_instance_statistics, score: 0) { Gitlab::CurrentSettings.instance_statistics_visibility_private? } condition(:private_instance_statistics, score: 0) { Gitlab::CurrentSettings.instance_statistics_visibility_private? }
condition(:project_bot, scope: :user) { @user&.project_bot? }
rule { admin | (~private_instance_statistics & ~anonymous) } rule { admin | (~private_instance_statistics & ~anonymous) }
.enable :read_instance_statistics .enable :read_instance_statistics
...@@ -51,6 +53,11 @@ class GlobalPolicy < BasePolicy ...@@ -51,6 +53,11 @@ class GlobalPolicy < BasePolicy
prevent :use_slash_commands prevent :use_slash_commands
end end
rule { project_bot }.policy do
prevent :log_in
prevent :receive_notifications
end
rule { deactivated }.policy do rule { deactivated }.policy do
prevent :access_git prevent :access_git
prevent :access_api prevent :access_api
......
...@@ -262,6 +262,7 @@ module EE ...@@ -262,6 +262,7 @@ module EE
def using_license_seat? def using_license_seat?
active? && active? &&
!internal? && !internal? &&
!project_bot? &&
has_current_license? && has_current_license? &&
paid_in_current_license? paid_in_current_license?
end end
......
...@@ -27,6 +27,10 @@ FactoryBot.define do ...@@ -27,6 +27,10 @@ FactoryBot.define do
user_type { :alert_bot } user_type { :alert_bot }
end end
trait :project_bot do
user_type { :project_bot }
end
trait :external do trait :external do
external { true } external { true }
end end
......
...@@ -4357,18 +4357,19 @@ describe User, :do_not_mock_admin_mode do ...@@ -4357,18 +4357,19 @@ describe User, :do_not_mock_admin_mode do
describe 'internal methods' do describe 'internal methods' do
let_it_be(:user) { create(:user) } let_it_be(:user) { create(:user) }
let!(:ghost) { described_class.ghost } let_it_be(:ghost) { described_class.ghost }
let!(:alert_bot) { described_class.alert_bot } let_it_be(:alert_bot) { described_class.alert_bot }
let!(:non_internal) { [user] } let_it_be(:project_bot) { create(:user, :project_bot) }
let!(:internal) { [ghost, alert_bot] } let_it_be(:non_internal) { [user, project_bot] }
let_it_be(:internal) { [ghost, alert_bot] }
it 'returns internal users' do it 'returns internal users' do
expect(described_class.internal).to eq(internal) expect(described_class.internal).to match_array(internal)
expect(internal.all?(&:internal?)).to eq(true) expect(internal.all?(&:internal?)).to eq(true)
end end
it 'returns non internal users' do it 'returns non internal users' do
expect(described_class.non_internal).to eq(non_internal) expect(described_class.non_internal).to match_array(non_internal)
expect(non_internal.all?(&:internal?)).to eq(false) expect(non_internal.all?(&:internal?)).to eq(false)
end end
...@@ -4420,9 +4421,12 @@ describe User, :do_not_mock_admin_mode do ...@@ -4420,9 +4421,12 @@ describe User, :do_not_mock_admin_mode do
it 'returns corresponding users' do it 'returns corresponding users' do
human = create(:user) human = create(:user)
bot = create(:user, :bot) bot = create(:user, :bot)
project_bot = create(:user, :project_bot)
expect(described_class.humans).to match_array([human]) expect(described_class.humans).to match_array([human])
expect(described_class.bots).to match_array([bot]) expect(described_class.bots).to match_array([bot, project_bot])
expect(described_class.bots_without_project_bot).to match_array([bot])
expect(described_class.with_project_bots).to match_array([human, project_bot])
end end
end end
......
# frozen_string_literal: true
require 'spec_helper'
describe UserTypeEnums do
it '.types' do
expect(described_class.types.keys).to include('alert_bot', 'project_bot', 'human', 'ghost')
end
it '.bots' do
expect(described_class.bots.keys).to include('alert_bot', 'project_bot')
end
end
...@@ -5,6 +5,7 @@ require 'spec_helper' ...@@ -5,6 +5,7 @@ require 'spec_helper'
describe GlobalPolicy do describe GlobalPolicy do
include TermsHelper include TermsHelper
let_it_be(:project_bot) { create(:user, :project_bot) }
let(:current_user) { create(:user) } let(:current_user) { create(:user) }
let(:user) { create(:user) } let(:user) { create(:user) }
...@@ -120,6 +121,12 @@ describe GlobalPolicy do ...@@ -120,6 +121,12 @@ describe GlobalPolicy do
it { is_expected.to be_allowed(:access_api) } it { is_expected.to be_allowed(:access_api) }
end end
context 'project bot' do
let(:current_user) { project_bot }
it { is_expected.to be_allowed(:access_api) }
end
context 'when terms are enforced' do context 'when terms are enforced' do
before do before do
enforce_terms enforce_terms
...@@ -203,6 +210,12 @@ describe GlobalPolicy do ...@@ -203,6 +210,12 @@ describe GlobalPolicy do
it { is_expected.not_to be_allowed(:receive_notifications) } it { is_expected.not_to be_allowed(:receive_notifications) }
end end
context 'project bot' do
let(:current_user) { project_bot }
it { is_expected.not_to be_allowed(:receive_notifications) }
end
end end
describe 'git access' do describe 'git access' do
...@@ -265,6 +278,12 @@ describe GlobalPolicy do ...@@ -265,6 +278,12 @@ describe GlobalPolicy do
it { is_expected.to be_allowed(:access_git) } it { is_expected.to be_allowed(:access_git) }
end end
end end
context 'project bot' do
let(:current_user) { project_bot }
it { is_expected.to be_allowed(:access_git) }
end
end end
describe 'read instance metadata' do describe 'read instance metadata' do
...@@ -361,6 +380,12 @@ describe GlobalPolicy do ...@@ -361,6 +380,12 @@ describe GlobalPolicy do
it { is_expected.not_to be_allowed(:use_slash_commands) } it { is_expected.not_to be_allowed(:use_slash_commands) }
end end
context 'project bot' do
let(:current_user) { project_bot }
it { is_expected.to be_allowed(:use_slash_commands) }
end
end end
describe 'create_snippet' do describe 'create_snippet' do
...@@ -380,4 +405,12 @@ describe GlobalPolicy do ...@@ -380,4 +405,12 @@ describe GlobalPolicy do
it { is_expected.not_to be_allowed(:create_snippet) } it { is_expected.not_to be_allowed(:create_snippet) }
end end
end end
describe 'log in' do
context 'project bot' do
let(:current_user) { project_bot }
it { is_expected.not_to be_allowed(:log_in) }
end
end
end 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