Commit 11a340f2 authored by Matthias Käppler's avatar Matthias Käppler

Merge branch 'runner-token-expiration-interval-settings' into 'master'

Add runner token expiration interval settings

See merge request gitlab-org/gitlab!77884
parents 5e0bcd6d d62621aa
...@@ -78,6 +78,10 @@ class ApplicationSetting < ApplicationRecord ...@@ -78,6 +78,10 @@ class ApplicationSetting < ApplicationRecord
chronic_duration_attr_writer :archive_builds_in_human_readable, :archive_builds_in_seconds chronic_duration_attr_writer :archive_builds_in_human_readable, :archive_builds_in_seconds
chronic_duration_attr :runner_token_expiration_interval_human_readable, :runner_token_expiration_interval
chronic_duration_attr :group_runner_token_expiration_interval_human_readable, :group_runner_token_expiration_interval
chronic_duration_attr :project_runner_token_expiration_interval_human_readable, :project_runner_token_expiration_interval
validates :grafana_url, validates :grafana_url,
system_hook_url: { system_hook_url: {
blocked_message: "is blocked: %{exception_message}. " + GRAFANA_URL_ERROR_MESSAGE blocked_message: "is blocked: %{exception_message}. " + GRAFANA_URL_ERROR_MESSAGE
......
# frozen_string_literal: true
module RunnerTokenExpirationInterval
extend ActiveSupport::Concern
def enforced_runner_token_expiration_interval_human_readable
interval = enforced_runner_token_expiration_interval
ChronicDuration.output(interval, format: :short) if interval
end
def effective_runner_token_expiration_interval
[
enforced_runner_token_expiration_interval,
runner_token_expiration_interval&.seconds
].compact.min
end
def effective_runner_token_expiration_interval_human_readable
interval = effective_runner_token_expiration_interval
ChronicDuration.output(interval, format: :short) if interval
end
end
...@@ -17,6 +17,8 @@ class Group < Namespace ...@@ -17,6 +17,8 @@ class Group < Namespace
include GroupAPICompatibility include GroupAPICompatibility
include EachBatch include EachBatch
include BulkMemberAccessLoad include BulkMemberAccessLoad
include ChronicDurationAttribute
include RunnerTokenExpirationInterval
def self.sti_name def self.sti_name
'Group' 'Group'
...@@ -91,6 +93,9 @@ class Group < Namespace ...@@ -91,6 +93,9 @@ class Group < Namespace
has_many :group_callouts, class_name: 'Users::GroupCallout', foreign_key: :group_id has_many :group_callouts, class_name: 'Users::GroupCallout', foreign_key: :group_id
delegate :prevent_sharing_groups_outside_hierarchy, :new_user_signups_cap, :setup_for_company, :jobs_to_be_done, to: :namespace_settings delegate :prevent_sharing_groups_outside_hierarchy, :new_user_signups_cap, :setup_for_company, :jobs_to_be_done, to: :namespace_settings
delegate :runner_token_expiration_interval, :runner_token_expiration_interval=, :runner_token_expiration_interval_human_readable, :runner_token_expiration_interval_human_readable=, to: :namespace_settings, allow_nil: true
delegate :subgroup_runner_token_expiration_interval, :subgroup_runner_token_expiration_interval=, :subgroup_runner_token_expiration_interval_human_readable, :subgroup_runner_token_expiration_interval_human_readable=, to: :namespace_settings, allow_nil: true
delegate :project_runner_token_expiration_interval, :project_runner_token_expiration_interval=, :project_runner_token_expiration_interval_human_readable, :project_runner_token_expiration_interval_human_readable=, to: :namespace_settings, allow_nil: true
has_one :crm_settings, class_name: 'Group::CrmSettings', inverse_of: :group has_one :crm_settings, class_name: 'Group::CrmSettings', inverse_of: :group
...@@ -788,6 +793,17 @@ class Group < Namespace ...@@ -788,6 +793,17 @@ class Group < Namespace
shared_with_group_links.preload_shared_with_groups.filter { |link| Ability.allowed?(user, :read_group, link.shared_with_group) } shared_with_group_links.preload_shared_with_groups.filter { |link| Ability.allowed?(user, :read_group, link.shared_with_group) }
end end
def enforced_runner_token_expiration_interval
all_parent_groups = Gitlab::ObjectHierarchy.new(Group.where(id: id)).ancestors
all_group_settings = NamespaceSetting.where(namespace_id: all_parent_groups)
group_interval = all_group_settings.where.not(subgroup_runner_token_expiration_interval: nil).minimum(:subgroup_runner_token_expiration_interval)&.seconds
[
Gitlab::CurrentSettings.group_runner_token_expiration_interval&.seconds,
group_interval
].compact.min
end
private private
def max_member_access(user_ids) def max_member_access(user_ids)
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
class NamespaceSetting < ApplicationRecord class NamespaceSetting < ApplicationRecord
include CascadingNamespaceSettingAttribute include CascadingNamespaceSettingAttribute
include Sanitizable include Sanitizable
include ChronicDurationAttribute
cascading_attr :delayed_project_removal cascading_attr :delayed_project_removal
...@@ -16,10 +17,15 @@ class NamespaceSetting < ApplicationRecord ...@@ -16,10 +17,15 @@ class NamespaceSetting < ApplicationRecord
enum jobs_to_be_done: { basics: 0, move_repository: 1, code_storage: 2, exploring: 3, ci: 4, other: 5 }, _suffix: true enum jobs_to_be_done: { basics: 0, move_repository: 1, code_storage: 2, exploring: 3, ci: 4, other: 5 }, _suffix: true
chronic_duration_attr :runner_token_expiration_interval_human_readable, :runner_token_expiration_interval
chronic_duration_attr :subgroup_runner_token_expiration_interval_human_readable, :subgroup_runner_token_expiration_interval
chronic_duration_attr :project_runner_token_expiration_interval_human_readable, :project_runner_token_expiration_interval
NAMESPACE_SETTINGS_PARAMS = [:default_branch_name, :delayed_project_removal, NAMESPACE_SETTINGS_PARAMS = [:default_branch_name, :delayed_project_removal,
:lock_delayed_project_removal, :resource_access_token_creation_allowed, :lock_delayed_project_removal, :resource_access_token_creation_allowed,
:prevent_sharing_groups_outside_hierarchy, :new_user_signups_cap, :prevent_sharing_groups_outside_hierarchy, :new_user_signups_cap,
:setup_for_company, :jobs_to_be_done].freeze :setup_for_company, :jobs_to_be_done, :runner_token_expiration_interval,
:subgroup_runner_token_expiration_interval, :project_runner_token_expiration_interval].freeze
self.primary_key = :namespace_id self.primary_key = :namespace_id
......
...@@ -37,6 +37,7 @@ class Project < ApplicationRecord ...@@ -37,6 +37,7 @@ class Project < ApplicationRecord
include EachBatch include EachBatch
include GitlabRoutingHelper include GitlabRoutingHelper
include BulkMemberAccessLoad include BulkMemberAccessLoad
include RunnerTokenExpirationInterval
extend Gitlab::Cache::RequestCache extend Gitlab::Cache::RequestCache
extend Gitlab::Utils::Override extend Gitlab::Utils::Override
...@@ -454,6 +455,7 @@ class Project < ApplicationRecord ...@@ -454,6 +455,7 @@ class Project < ApplicationRecord
delegate :job_token_scope_enabled, :job_token_scope_enabled=, to: :ci_cd_settings, prefix: :ci, allow_nil: true delegate :job_token_scope_enabled, :job_token_scope_enabled=, to: :ci_cd_settings, prefix: :ci, allow_nil: true
delegate :keep_latest_artifact, :keep_latest_artifact=, to: :ci_cd_settings, allow_nil: true delegate :keep_latest_artifact, :keep_latest_artifact=, to: :ci_cd_settings, allow_nil: true
delegate :restrict_user_defined_variables, :restrict_user_defined_variables=, to: :ci_cd_settings, allow_nil: true delegate :restrict_user_defined_variables, :restrict_user_defined_variables=, to: :ci_cd_settings, allow_nil: true
delegate :runner_token_expiration_interval, :runner_token_expiration_interval=, :runner_token_expiration_interval_human_readable, :runner_token_expiration_interval_human_readable=, to: :ci_cd_settings, allow_nil: true
delegate :actual_limits, :actual_plan_name, :actual_plan, to: :namespace, allow_nil: true delegate :actual_limits, :actual_plan_name, :actual_plan, to: :namespace, allow_nil: true
delegate :allow_merge_on_skipped_pipeline, :allow_merge_on_skipped_pipeline?, delegate :allow_merge_on_skipped_pipeline, :allow_merge_on_skipped_pipeline?,
:allow_merge_on_skipped_pipeline=, :has_confluence?, :has_shimo?, :allow_merge_on_skipped_pipeline=, :has_confluence?, :has_shimo?,
...@@ -2697,6 +2699,10 @@ class Project < ApplicationRecord ...@@ -2697,6 +2699,10 @@ class Project < ApplicationRecord
ci_cd_settings.keep_latest_artifact? ci_cd_settings.keep_latest_artifact?
end end
def runner_token_expiration_interval
ci_cd_settings&.runner_token_expiration_interval
end
def group_runners_enabled? def group_runners_enabled?
return false unless ci_cd_settings return false unless ci_cd_settings
...@@ -2728,6 +2734,17 @@ class Project < ApplicationRecord ...@@ -2728,6 +2734,17 @@ class Project < ApplicationRecord
end end
end end
def enforced_runner_token_expiration_interval
all_parent_groups = Gitlab::ObjectHierarchy.new(Group.where(id: group)).base_and_ancestors
all_group_settings = NamespaceSetting.where(namespace_id: all_parent_groups)
group_interval = all_group_settings.where.not(project_runner_token_expiration_interval: nil).minimum(:project_runner_token_expiration_interval)&.seconds
[
Gitlab::CurrentSettings.project_runner_token_expiration_interval&.seconds,
group_interval
].compact.min
end
private private
# overridden in EE # overridden in EE
......
# frozen_string_literal: true # frozen_string_literal: true
class ProjectCiCdSetting < ApplicationRecord class ProjectCiCdSetting < ApplicationRecord
include ChronicDurationAttribute
belongs_to :project, inverse_of: :ci_cd_settings belongs_to :project, inverse_of: :ci_cd_settings
DEFAULT_GIT_DEPTH = 20 DEFAULT_GIT_DEPTH = 20
...@@ -17,6 +19,8 @@ class ProjectCiCdSetting < ApplicationRecord ...@@ -17,6 +19,8 @@ class ProjectCiCdSetting < ApplicationRecord
default_value_for :forward_deployment_enabled, true default_value_for :forward_deployment_enabled, true
chronic_duration_attr :runner_token_expiration_interval_human_readable, :runner_token_expiration_interval
def forward_deployment_enabled? def forward_deployment_enabled?
super && ::Feature.enabled?(:forward_deployment_enabled, project, default_enabled: true) super && ::Feature.enabled?(:forward_deployment_enabled, project, default_enabled: true)
end end
......
# frozen_string_literal: true
class AddRunnerTokenExpirationIntervalSettingsToApplicationSettings < Gitlab::Database::Migration[1.0]
def change
[:runner_token_expiration_interval, :group_runner_token_expiration_interval, :project_runner_token_expiration_interval].each do |field|
add_column :application_settings, field, :integer
end
end
end
# frozen_string_literal: true
class AddRunnerTokenExpirationIntervalSettingsToNamespaceSettings < Gitlab::Database::Migration[1.0]
enable_lock_retries!
def change
[:runner_token_expiration_interval, :subgroup_runner_token_expiration_interval, :project_runner_token_expiration_interval].each do |field|
add_column :namespace_settings, field, :integer
end
end
end
# frozen_string_literal: true
class AddRunnerTokenExpirationIntervalSettingsToProjectSettings < Gitlab::Database::Migration[1.0]
enable_lock_retries!
def change
add_column :project_ci_cd_settings, :runner_token_expiration_interval, :integer
end
end
88935eee0781ee1faaf52e3bc89dc5c490c2095d6ccf83e4fd4186641507c173
\ No newline at end of file
aa73b04aa355111564cdc7adb036a2030a28fbb3b524c3b3dbb8248e27b845d7
\ No newline at end of file
4d5adffe1a3e835d6d23f6bd9634993c778fef23d134552d54b003af2a3ff4da
\ No newline at end of file
...@@ -10483,6 +10483,9 @@ CREATE TABLE application_settings ( ...@@ -10483,6 +10483,9 @@ CREATE TABLE application_settings (
future_subscriptions jsonb DEFAULT '[]'::jsonb NOT NULL, future_subscriptions jsonb DEFAULT '[]'::jsonb NOT NULL,
user_email_lookup_limit integer DEFAULT 60 NOT NULL, user_email_lookup_limit integer DEFAULT 60 NOT NULL,
packages_cleanup_package_file_worker_capacity smallint DEFAULT 2 NOT NULL, packages_cleanup_package_file_worker_capacity smallint DEFAULT 2 NOT NULL,
runner_token_expiration_interval integer,
group_runner_token_expiration_interval integer,
project_runner_token_expiration_interval integer,
CONSTRAINT app_settings_container_reg_cleanup_tags_max_list_size_positive CHECK ((container_registry_cleanup_tags_service_max_list_size >= 0)), CONSTRAINT app_settings_container_reg_cleanup_tags_max_list_size_positive CHECK ((container_registry_cleanup_tags_service_max_list_size >= 0)),
CONSTRAINT app_settings_dep_proxy_ttl_policies_worker_capacity_positive CHECK ((dependency_proxy_ttl_group_policy_worker_capacity >= 0)), CONSTRAINT app_settings_dep_proxy_ttl_policies_worker_capacity_positive CHECK ((dependency_proxy_ttl_group_policy_worker_capacity >= 0)),
CONSTRAINT app_settings_ext_pipeline_validation_service_url_text_limit CHECK ((char_length(external_pipeline_validation_service_url) <= 255)), CONSTRAINT app_settings_ext_pipeline_validation_service_url_text_limit CHECK ((char_length(external_pipeline_validation_service_url) <= 255)),
...@@ -16505,6 +16508,9 @@ CREATE TABLE namespace_settings ( ...@@ -16505,6 +16508,9 @@ CREATE TABLE namespace_settings (
new_user_signups_cap integer, new_user_signups_cap integer,
setup_for_company boolean, setup_for_company boolean,
jobs_to_be_done smallint, jobs_to_be_done smallint,
runner_token_expiration_interval integer,
subgroup_runner_token_expiration_interval integer,
project_runner_token_expiration_interval integer,
CONSTRAINT check_0ba93c78c7 CHECK ((char_length(default_branch_name) <= 255)) CONSTRAINT check_0ba93c78c7 CHECK ((char_length(default_branch_name) <= 255))
); );
...@@ -18169,7 +18175,8 @@ CREATE TABLE project_ci_cd_settings ( ...@@ -18169,7 +18175,8 @@ CREATE TABLE project_ci_cd_settings (
auto_rollback_enabled boolean DEFAULT false NOT NULL, auto_rollback_enabled boolean DEFAULT false NOT NULL,
keep_latest_artifact boolean DEFAULT true NOT NULL, keep_latest_artifact boolean DEFAULT true NOT NULL,
restrict_user_defined_variables boolean DEFAULT false NOT NULL, restrict_user_defined_variables boolean DEFAULT false NOT NULL,
job_token_scope_enabled boolean DEFAULT false NOT NULL job_token_scope_enabled boolean DEFAULT false NOT NULL,
runner_token_expiration_interval integer
); );
CREATE SEQUENCE project_ci_cd_settings_id_seq CREATE SEQUENCE project_ci_cd_settings_id_seq
...@@ -132,6 +132,7 @@ module API ...@@ -132,6 +132,7 @@ module API
Ability.allowed?(options[:current_user], :change_repository_storage, project) Ability.allowed?(options[:current_user], :change_repository_storage, project)
} }
expose :keep_latest_artifacts_available?, as: :keep_latest_artifact expose :keep_latest_artifacts_available?, as: :keep_latest_artifact
expose :runner_token_expiration_interval
# rubocop: disable CodeReuse/ActiveRecord # rubocop: disable CodeReuse/ActiveRecord
def self.preload_resource(project) def self.preload_resource(project)
......
...@@ -120,6 +120,7 @@ included_attributes: ...@@ -120,6 +120,7 @@ included_attributes:
- :name - :name
ci_cd_settings: ci_cd_settings:
- :group_runners_enabled - :group_runners_enabled
- :runner_token_expiration_interval
metrics_setting: metrics_setting:
- :dashboard_timezone - :dashboard_timezone
- :external_dashboard_url - :external_dashboard_url
......
...@@ -49,6 +49,8 @@ FactoryBot.define do ...@@ -49,6 +49,8 @@ FactoryBot.define do
forward_deployment_enabled { nil } forward_deployment_enabled { nil }
restrict_user_defined_variables { nil } restrict_user_defined_variables { nil }
ci_job_token_scope_enabled { nil } ci_job_token_scope_enabled { nil }
runner_token_expiration_interval { nil }
runner_token_expiration_interval_human_readable { nil }
end end
after(:build) do |project, evaluator| after(:build) do |project, evaluator|
...@@ -92,6 +94,8 @@ FactoryBot.define do ...@@ -92,6 +94,8 @@ FactoryBot.define do
project.keep_latest_artifact = evaluator.keep_latest_artifact unless evaluator.keep_latest_artifact.nil? project.keep_latest_artifact = evaluator.keep_latest_artifact unless evaluator.keep_latest_artifact.nil?
project.restrict_user_defined_variables = evaluator.restrict_user_defined_variables unless evaluator.restrict_user_defined_variables.nil? project.restrict_user_defined_variables = evaluator.restrict_user_defined_variables unless evaluator.restrict_user_defined_variables.nil?
project.ci_job_token_scope_enabled = evaluator.ci_job_token_scope_enabled unless evaluator.ci_job_token_scope_enabled.nil? project.ci_job_token_scope_enabled = evaluator.ci_job_token_scope_enabled unless evaluator.ci_job_token_scope_enabled.nil?
project.runner_token_expiration_interval = evaluator.runner_token_expiration_interval unless evaluator.runner_token_expiration_interval.nil?
project.runner_token_expiration_interval_human_readable = evaluator.runner_token_expiration_interval_human_readable unless evaluator.runner_token_expiration_interval_human_readable.nil?
if evaluator.import_status if evaluator.import_status
import_state = project.import_state || project.build_import_state import_state = project.import_state || project.build_import_state
......
...@@ -692,6 +692,7 @@ Badge: ...@@ -692,6 +692,7 @@ Badge:
- type - type
ProjectCiCdSetting: ProjectCiCdSetting:
- group_runners_enabled - group_runners_enabled
- runner_token_expiration_interval
ProjectSetting: ProjectSetting:
- allow_merge_on_skipped_pipeline - allow_merge_on_skipped_pipeline
- has_confluence - has_confluence
......
...@@ -4,6 +4,7 @@ require 'spec_helper' ...@@ -4,6 +4,7 @@ require 'spec_helper'
RSpec.describe Group do RSpec.describe Group do
include ReloadHelpers include ReloadHelpers
include StubGitlabCalls
let!(:group) { create(:group) } let!(:group) { create(:group) }
...@@ -2930,4 +2931,222 @@ RSpec.describe Group do ...@@ -2930,4 +2931,222 @@ RSpec.describe Group do
end end
end end
end end
describe '#enforced_runner_token_expiration_interval and #effective_runner_token_expiration_interval' do
shared_examples 'no enforced expiration interval' do
it { expect(subject.enforced_runner_token_expiration_interval).to be_nil }
end
shared_examples 'enforced expiration interval' do |enforced_interval:|
it { expect(subject.enforced_runner_token_expiration_interval).to eq(enforced_interval) }
end
shared_examples 'no effective expiration interval' do
it { expect(subject.effective_runner_token_expiration_interval).to be_nil }
end
shared_examples 'effective expiration interval' do |effective_interval:|
it { expect(subject.effective_runner_token_expiration_interval).to eq(effective_interval) }
end
context 'when there is no interval in group settings' do
let_it_be(:group) { create(:group) }
subject { group }
it_behaves_like 'no enforced expiration interval'
it_behaves_like 'no effective expiration interval'
end
context 'when there is a group interval' do
let(:group_settings) { create(:namespace_settings, runner_token_expiration_interval: 3.days.to_i) }
subject { create(:group, namespace_settings: group_settings) }
it_behaves_like 'no enforced expiration interval'
it_behaves_like 'effective expiration interval', effective_interval: 3.days
end
# runner_token_expiration_interval should not affect the expiration interval, only
# group_runner_token_expiration_interval should.
context 'when there is a site-wide enforced shared interval' do
before do
stub_application_setting(runner_token_expiration_interval: 5.days.to_i)
end
let_it_be(:group) { create(:group) }
subject { group }
it_behaves_like 'no enforced expiration interval'
it_behaves_like 'no effective expiration interval'
end
context 'when there is a site-wide enforced group interval' do
before do
stub_application_setting(group_runner_token_expiration_interval: 5.days.to_i)
end
let_it_be(:group) { create(:group) }
subject { group }
it_behaves_like 'enforced expiration interval', enforced_interval: 5.days
it_behaves_like 'effective expiration interval', effective_interval: 5.days
end
# project_runner_token_expiration_interval should not affect the expiration interval, only
# group_runner_token_expiration_interval should.
context 'when there is a site-wide enforced project interval' do
before do
stub_application_setting(project_runner_token_expiration_interval: 5.days.to_i)
end
let_it_be(:group) { create(:group) }
subject { group }
it_behaves_like 'no enforced expiration interval'
it_behaves_like 'no effective expiration interval'
end
# runner_token_expiration_interval should not affect the expiration interval, only
# subgroup_runner_token_expiration_interval should.
context 'when there is a grandparent group enforced group interval' do
let_it_be(:grandparent_group_settings) { create(:namespace_settings, runner_token_expiration_interval: 4.days.to_i) }
let_it_be(:grandparent_group) { create(:group, namespace_settings: grandparent_group_settings) }
let_it_be(:parent_group) { create(:group, parent: grandparent_group) }
let_it_be(:subgroup) { create(:group, parent: parent_group) }
subject { subgroup }
it_behaves_like 'no enforced expiration interval'
it_behaves_like 'no effective expiration interval'
end
context 'when there is a grandparent group enforced subgroup interval' do
let_it_be(:grandparent_group_settings) { create(:namespace_settings, subgroup_runner_token_expiration_interval: 4.days.to_i) }
let_it_be(:grandparent_group) { create(:group, namespace_settings: grandparent_group_settings) }
let_it_be(:parent_group) { create(:group, parent: grandparent_group) }
let_it_be(:subgroup) { create(:group, parent: parent_group) }
subject { subgroup }
it_behaves_like 'enforced expiration interval', enforced_interval: 4.days
it_behaves_like 'effective expiration interval', effective_interval: 4.days
end
# project_runner_token_expiration_interval should not affect the expiration interval, only
# subgroup_runner_token_expiration_interval should.
context 'when there is a grandparent group enforced project interval' do
let_it_be(:grandparent_group_settings) { create(:namespace_settings, project_runner_token_expiration_interval: 4.days.to_i) }
let_it_be(:grandparent_group) { create(:group, namespace_settings: grandparent_group_settings) }
let_it_be(:parent_group) { create(:group, parent: grandparent_group) }
let_it_be(:subgroup) { create(:group, parent: parent_group) }
subject { subgroup }
it_behaves_like 'no enforced expiration interval'
it_behaves_like 'no effective expiration interval'
end
context 'when there is a parent group enforced interval overridden by group interval' do
let_it_be(:parent_group_settings) { create(:namespace_settings, subgroup_runner_token_expiration_interval: 5.days.to_i) }
let_it_be(:parent_group) { create(:group, namespace_settings: parent_group_settings) }
let_it_be(:group_settings) { create(:namespace_settings, runner_token_expiration_interval: 4.days.to_i) }
let_it_be(:subgroup_with_settings) { create(:group, parent: parent_group, namespace_settings: group_settings) }
subject { subgroup_with_settings }
it_behaves_like 'enforced expiration interval', enforced_interval: 5.days
it_behaves_like 'effective expiration interval', effective_interval: 4.days
it 'has human-readable expiration intervals' do
expect(subject.enforced_runner_token_expiration_interval_human_readable).to eq('5d')
expect(subject.effective_runner_token_expiration_interval_human_readable).to eq('4d')
end
end
context 'when site-wide enforced interval overrides group interval' do
before do
stub_application_setting(group_runner_token_expiration_interval: 3.days.to_i)
end
let_it_be(:group_settings) { create(:namespace_settings, runner_token_expiration_interval: 4.days.to_i) }
let_it_be(:group_with_settings) { create(:group, namespace_settings: group_settings) }
subject { group_with_settings }
it_behaves_like 'enforced expiration interval', enforced_interval: 3.days
it_behaves_like 'effective expiration interval', effective_interval: 3.days
end
context 'when group interval overrides site-wide enforced interval' do
before do
stub_application_setting(group_runner_token_expiration_interval: 5.days.to_i)
end
let_it_be(:group_settings) { create(:namespace_settings, runner_token_expiration_interval: 4.days.to_i) }
let_it_be(:group_with_settings) { create(:group, namespace_settings: group_settings) }
subject { group_with_settings }
it_behaves_like 'enforced expiration interval', enforced_interval: 5.days
it_behaves_like 'effective expiration interval', effective_interval: 4.days
end
context 'when site-wide enforced interval overrides parent group enforced interval' do
before do
stub_application_setting(group_runner_token_expiration_interval: 3.days.to_i)
end
let_it_be(:parent_group_settings) { create(:namespace_settings, subgroup_runner_token_expiration_interval: 4.days.to_i) }
let_it_be(:parent_group) { create(:group, namespace_settings: parent_group_settings) }
let_it_be(:subgroup) { create(:group, parent: parent_group) }
subject { subgroup }
it_behaves_like 'enforced expiration interval', enforced_interval: 3.days
it_behaves_like 'effective expiration interval', effective_interval: 3.days
end
context 'when parent group enforced interval overrides site-wide enforced interval' do
before do
stub_application_setting(group_runner_token_expiration_interval: 5.days.to_i)
end
let_it_be(:parent_group_settings) { create(:namespace_settings, subgroup_runner_token_expiration_interval: 4.days.to_i) }
let_it_be(:parent_group) { create(:group, namespace_settings: parent_group_settings) }
let_it_be(:subgroup) { create(:group, parent: parent_group) }
subject { subgroup }
it_behaves_like 'enforced expiration interval', enforced_interval: 4.days
it_behaves_like 'effective expiration interval', effective_interval: 4.days
end
# Unrelated groups should not affect the expiration interval.
context 'when there is an enforced group interval in an unrelated group' do
let_it_be(:unrelated_group_settings) { create(:namespace_settings, subgroup_runner_token_expiration_interval: 4.days.to_i) }
let_it_be(:unrelated_group) { create(:group, namespace_settings: unrelated_group_settings) }
let_it_be(:group) { create(:group) }
subject { group }
it_behaves_like 'no enforced expiration interval'
it_behaves_like 'no effective expiration interval'
end
# Subgroups should not affect the parent group expiration interval.
context 'when there is an enforced group interval in a subgroup' do
let_it_be(:subgroup_settings) { create(:namespace_settings, subgroup_runner_token_expiration_interval: 4.days.to_i) }
let_it_be(:subgroup) { create(:group, parent: group, namespace_settings: subgroup_settings) }
let_it_be(:group) { create(:group) }
subject { group }
it_behaves_like 'no enforced expiration interval'
it_behaves_like 'no effective expiration interval'
end
end
end end
...@@ -7,6 +7,7 @@ RSpec.describe Project, factory_default: :keep do ...@@ -7,6 +7,7 @@ RSpec.describe Project, factory_default: :keep do
include GitHelpers include GitHelpers
include ExternalAuthorizationServiceHelpers include ExternalAuthorizationServiceHelpers
include ReloadHelpers include ReloadHelpers
include StubGitlabCalls
using RSpec::Parameterized::TableSyntax using RSpec::Parameterized::TableSyntax
let_it_be(:namespace) { create_default(:namespace).freeze } let_it_be(:namespace) { create_default(:namespace).freeze }
...@@ -7455,6 +7456,258 @@ RSpec.describe Project, factory_default: :keep do ...@@ -7455,6 +7456,258 @@ RSpec.describe Project, factory_default: :keep do
end end
end end
describe '#enforced_runner_token_expiration_interval and #effective_runner_token_expiration_interval' do
shared_examples 'no enforced expiration interval' do
it { expect(subject.enforced_runner_token_expiration_interval).to be_nil }
end
shared_examples 'enforced expiration interval' do |enforced_interval:|
it { expect(subject.enforced_runner_token_expiration_interval).to eq(enforced_interval) }
end
shared_examples 'no effective expiration interval' do
it { expect(subject.effective_runner_token_expiration_interval).to be_nil }
end
shared_examples 'effective expiration interval' do |effective_interval:|
it { expect(subject.effective_runner_token_expiration_interval).to eq(effective_interval) }
end
context 'when there is no interval' do
let_it_be(:project) { create(:project) }
subject { project }
it_behaves_like 'no enforced expiration interval'
it_behaves_like 'no effective expiration interval'
end
context 'when there is a project interval' do
let_it_be(:project) { create(:project, runner_token_expiration_interval: 3.days.to_i) }
subject { project }
it_behaves_like 'no enforced expiration interval'
it_behaves_like 'effective expiration interval', effective_interval: 3.days
end
# runner_token_expiration_interval should not affect the expiration interval, only
# project_runner_token_expiration_interval should.
context 'when there is a site-wide enforced shared interval' do
before do
stub_application_setting(runner_token_expiration_interval: 5.days.to_i)
end
let_it_be(:project) { create(:project) }
subject { project }
it_behaves_like 'no enforced expiration interval'
it_behaves_like 'no effective expiration interval'
end
# group_runner_token_expiration_interval should not affect the expiration interval, only
# project_runner_token_expiration_interval should.
context 'when there is a site-wide enforced group interval' do
before do
stub_application_setting(group_runner_token_expiration_interval: 5.days.to_i)
end
let_it_be(:project) { create(:project) }
subject { project }
it_behaves_like 'no enforced expiration interval'
it_behaves_like 'no effective expiration interval'
end
context 'when there is a site-wide enforced project interval' do
before do
stub_application_setting(project_runner_token_expiration_interval: 5.days.to_i)
end
let_it_be(:project) { create(:project) }
subject { project }
it_behaves_like 'enforced expiration interval', enforced_interval: 5.days
it_behaves_like 'effective expiration interval', effective_interval: 5.days
end
# runner_token_expiration_interval should not affect the expiration interval, only
# project_runner_token_expiration_interval should.
context 'when there is a group-enforced group interval' do
let_it_be(:group_settings) { create(:namespace_settings, runner_token_expiration_interval: 4.days.to_i) }
let_it_be(:group) { create(:group, namespace_settings: group_settings) }
let_it_be(:project) { create(:project, group: group) }
subject { project }
it_behaves_like 'no enforced expiration interval'
it_behaves_like 'no effective expiration interval'
end
# subgroup_runner_token_expiration_interval should not affect the expiration interval, only
# project_runner_token_expiration_interval should.
context 'when there is a group-enforced subgroup interval' do
let_it_be(:group_settings) { create(:namespace_settings, subgroup_runner_token_expiration_interval: 4.days.to_i) }
let_it_be(:group) { create(:group, namespace_settings: group_settings) }
let_it_be(:project) { create(:project, group: group) }
subject { project }
it_behaves_like 'no enforced expiration interval'
it_behaves_like 'no effective expiration interval'
end
context 'when there is an owner group-enforced project interval' do
let_it_be(:group_settings) { create(:namespace_settings, project_runner_token_expiration_interval: 4.days.to_i) }
let_it_be(:group) { create(:group, namespace_settings: group_settings) }
let_it_be(:project) { create(:project, group: group) }
subject { project }
it_behaves_like 'enforced expiration interval', enforced_interval: 4.days
it_behaves_like 'effective expiration interval', effective_interval: 4.days
end
context 'when there is a grandparent group-enforced interval' do
let_it_be(:grandparent_group_settings) { create(:namespace_settings, project_runner_token_expiration_interval: 3.days.to_i) }
let_it_be(:grandparent_group) { create(:group, namespace_settings: grandparent_group_settings) }
let_it_be(:parent_group_settings) { create(:namespace_settings) }
let_it_be(:parent_group) { create(:group, parent: grandparent_group, namespace_settings: parent_group_settings) }
let_it_be(:group_settings) { create(:namespace_settings, project_runner_token_expiration_interval: 4.days.to_i) }
let_it_be(:group) { create(:group, parent: parent_group, namespace_settings: group_settings) }
let_it_be(:project) { create(:project, group: group) }
subject { project }
it_behaves_like 'enforced expiration interval', enforced_interval: 3.days
it_behaves_like 'effective expiration interval', effective_interval: 3.days
end
context 'when there is a parent group-enforced interval overridden by group-enforced interval' do
let_it_be(:parent_group_settings) { create(:namespace_settings, project_runner_token_expiration_interval: 5.days.to_i) }
let_it_be(:parent_group) { create(:group, namespace_settings: parent_group_settings) }
let_it_be(:group_settings) { create(:namespace_settings, project_runner_token_expiration_interval: 4.days.to_i) }
let_it_be(:group) { create(:group, parent: parent_group, namespace_settings: group_settings) }
let_it_be(:project) { create(:project, group: group) }
subject { project }
it_behaves_like 'enforced expiration interval', enforced_interval: 4.days
it_behaves_like 'effective expiration interval', effective_interval: 4.days
end
context 'when site-wide enforced interval overrides project interval' do
before do
stub_application_setting(project_runner_token_expiration_interval: 3.days.to_i)
end
let_it_be(:project) { create(:project, runner_token_expiration_interval: 4.days.to_i) }
subject { project }
it_behaves_like 'enforced expiration interval', enforced_interval: 3.days
it_behaves_like 'effective expiration interval', effective_interval: 3.days
end
context 'when project interval overrides site-wide enforced interval' do
before do
stub_application_setting(project_runner_token_expiration_interval: 5.days.to_i)
end
let_it_be(:project) { create(:project, runner_token_expiration_interval: 4.days.to_i) }
subject { project }
it_behaves_like 'enforced expiration interval', enforced_interval: 5.days
it_behaves_like 'effective expiration interval', effective_interval: 4.days
it 'has human-readable expiration intervals' do
expect(subject.enforced_runner_token_expiration_interval_human_readable).to eq('5d')
expect(subject.effective_runner_token_expiration_interval_human_readable).to eq('4d')
end
end
context 'when site-wide enforced interval overrides group-enforced interval' do
before do
stub_application_setting(project_runner_token_expiration_interval: 3.days.to_i)
end
let_it_be(:group_settings) { create(:namespace_settings, project_runner_token_expiration_interval: 4.days.to_i) }
let_it_be(:group) { create(:group, namespace_settings: group_settings) }
let_it_be(:project) { create(:project, group: group) }
subject { project }
it_behaves_like 'enforced expiration interval', enforced_interval: 3.days
it_behaves_like 'effective expiration interval', effective_interval: 3.days
end
context 'when group-enforced interval overrides site-wide enforced interval' do
before do
stub_application_setting(project_runner_token_expiration_interval: 5.days.to_i)
end
let_it_be(:group_settings) { create(:namespace_settings, project_runner_token_expiration_interval: 4.days.to_i) }
let_it_be(:group) { create(:group, namespace_settings: group_settings) }
let_it_be(:project) { create(:project, group: group) }
subject { project }
it_behaves_like 'enforced expiration interval', enforced_interval: 4.days
it_behaves_like 'effective expiration interval', effective_interval: 4.days
end
context 'when group-enforced interval overrides project interval' do
let_it_be(:group_settings) { create(:namespace_settings, project_runner_token_expiration_interval: 3.days.to_i) }
let_it_be(:group) { create(:group, namespace_settings: group_settings) }
let_it_be(:project) { create(:project, group: group, runner_token_expiration_interval: 4.days.to_i) }
subject { project }
it_behaves_like 'enforced expiration interval', enforced_interval: 3.days
it_behaves_like 'effective expiration interval', effective_interval: 3.days
end
context 'when project interval overrides group-enforced interval' do
let_it_be(:group_settings) { create(:namespace_settings, project_runner_token_expiration_interval: 5.days.to_i) }
let_it_be(:group) { create(:group, namespace_settings: group_settings) }
let_it_be(:project) { create(:project, group: group, runner_token_expiration_interval: 4.days.to_i) }
subject { project }
it_behaves_like 'enforced expiration interval', enforced_interval: 5.days
it_behaves_like 'effective expiration interval', effective_interval: 4.days
end
# Unrelated groups should not affect the expiration interval.
context 'when there is an enforced project interval in an unrelated group' do
let_it_be(:unrelated_group_settings) { create(:namespace_settings, project_runner_token_expiration_interval: 4.days.to_i) }
let_it_be(:unrelated_group) { create(:group, namespace_settings: unrelated_group_settings) }
let_it_be(:project) { create(:project) }
subject { project }
it_behaves_like 'no enforced expiration interval'
it_behaves_like 'no effective expiration interval'
end
# Subgroups should not affect the parent group expiration interval.
context 'when there is an enforced project interval in a subgroup' do
let_it_be(:group) { create(:group) }
let_it_be(:subgroup_settings) { create(:namespace_settings, project_runner_token_expiration_interval: 4.days.to_i) }
let_it_be(:subgroup) { create(:group, parent: group, namespace_settings: subgroup_settings) }
let_it_be(:project) { create(:project, group: group) }
subject { project }
it_behaves_like 'no enforced expiration interval'
it_behaves_like 'no effective expiration interval'
end
end
it_behaves_like 'it has loose foreign keys' do it_behaves_like 'it has loose foreign keys' do
let(:factory_name) { :project } let(:factory_name) { :project }
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