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
scope :with_dashboard, -> (dashboard) { where(dashboard: dashboard) }
scope :with_public_profile, -> { where(private_profile: false) }
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 :with_expiring_and_not_notified_personal_access_tokens, ->(at) do
......@@ -657,8 +658,10 @@ class User < ApplicationRecord
UserTypeEnums.bots.has_key?(user_type)
end
# The explicit check for project_bot will be removed with Bot Categorization
# Ref: https://gitlab.com/gitlab-org/gitlab/-/issues/213945
def internal?
ghost? || bot?
ghost? || (bot? && !project_bot?)
end
# We are transitioning from ghost boolean column to user_type
......@@ -668,12 +671,16 @@ class User < ApplicationRecord
ghost
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
where(ghost: true).or(bots)
where(ghost: true).or(bots_without_project_bot)
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
without_ghosts.not_bots
without_ghosts.with_project_bots
end
#
......
......@@ -6,7 +6,7 @@ module UserTypeEnums
end
def self.bots
@bots ||= { alert_bot: 2 }.with_indifferent_access
@bots ||= { alert_bot: 2, project_bot: 6 }.with_indifferent_access
end
end
......
......@@ -17,6 +17,8 @@ class GlobalPolicy < BasePolicy
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) }
.enable :read_instance_statistics
......@@ -51,6 +53,11 @@ class GlobalPolicy < BasePolicy
prevent :use_slash_commands
end
rule { project_bot }.policy do
prevent :log_in
prevent :receive_notifications
end
rule { deactivated }.policy do
prevent :access_git
prevent :access_api
......
......@@ -262,6 +262,7 @@ module EE
def using_license_seat?
active? &&
!internal? &&
!project_bot? &&
has_current_license? &&
paid_in_current_license?
end
......
......@@ -27,6 +27,10 @@ FactoryBot.define do
user_type { :alert_bot }
end
trait :project_bot do
user_type { :project_bot }
end
trait :external do
external { true }
end
......
......@@ -4357,18 +4357,19 @@ describe User, :do_not_mock_admin_mode do
describe 'internal methods' do
let_it_be(:user) { create(:user) }
let!(:ghost) { described_class.ghost }
let!(:alert_bot) { described_class.alert_bot }
let!(:non_internal) { [user] }
let!(:internal) { [ghost, alert_bot] }
let_it_be(:ghost) { described_class.ghost }
let_it_be(:alert_bot) { described_class.alert_bot }
let_it_be(:project_bot) { create(:user, :project_bot) }
let_it_be(:non_internal) { [user, project_bot] }
let_it_be(:internal) { [ghost, alert_bot] }
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)
end
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)
end
......@@ -4420,9 +4421,12 @@ describe User, :do_not_mock_admin_mode do
it 'returns corresponding users' do
human = create(:user)
bot = create(:user, :bot)
project_bot = create(:user, :project_bot)
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
......
# 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'
describe GlobalPolicy do
include TermsHelper
let_it_be(:project_bot) { create(:user, :project_bot) }
let(:current_user) { create(:user) }
let(:user) { create(:user) }
......@@ -120,6 +121,12 @@ describe GlobalPolicy do
it { is_expected.to be_allowed(:access_api) }
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
before do
enforce_terms
......@@ -203,6 +210,12 @@ describe GlobalPolicy do
it { is_expected.not_to be_allowed(:receive_notifications) }
end
context 'project bot' do
let(:current_user) { project_bot }
it { is_expected.not_to be_allowed(:receive_notifications) }
end
end
describe 'git access' do
......@@ -265,6 +278,12 @@ describe GlobalPolicy do
it { is_expected.to be_allowed(:access_git) }
end
end
context 'project bot' do
let(:current_user) { project_bot }
it { is_expected.to be_allowed(:access_git) }
end
end
describe 'read instance metadata' do
......@@ -361,6 +380,12 @@ describe GlobalPolicy do
it { is_expected.not_to be_allowed(:use_slash_commands) }
end
context 'project bot' do
let(:current_user) { project_bot }
it { is_expected.to be_allowed(:use_slash_commands) }
end
end
describe 'create_snippet' do
......@@ -380,4 +405,12 @@ describe GlobalPolicy do
it { is_expected.not_to be_allowed(:create_snippet) }
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
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