Commit 99aacbf5 authored by Fabio Pitino's avatar Fabio Pitino

Add project setting to toggle job token scope

Add column job_token_scope_enabled to ProjectCiCdSetting.
Use setting when checking inclusion of project in scope.

Changelog: added
parent a8016a6b
...@@ -22,6 +22,9 @@ module Ci ...@@ -22,6 +22,9 @@ module Ci
end end
def includes?(target_project) def includes?(target_project)
# if the setting is disabled any project is considered to be in scope.
return true unless source_project.ci_job_token_scope_enabled?
target_project.id == source_project.id || target_project.id == source_project.id ||
Ci::JobToken::ProjectScopeLink.from_project(source_project).to_project(target_project).exists? Ci::JobToken::ProjectScopeLink.from_project(source_project).to_project(target_project).exists?
end end
......
# frozen_string_literal: true
# The connection between a source project (which defines the job token scope)
# and a target project which is the one allowed to be accessed by the job token.
module Ci
module JobToken
class ScopeLink < ApplicationRecord
self.table_name = 'ci_job_token_scope_links'
belongs_to :source_project, class_name: 'Project'
belongs_to :target_project, class_name: 'Project'
belongs_to :added_by, class_name: 'User'
scope :from_project, ->(project) { where(source_project: project) }
scope :to_project, ->(project) { where(target_project: project) }
end
end
end
...@@ -426,6 +426,7 @@ class Project < ApplicationRecord ...@@ -426,6 +426,7 @@ class Project < ApplicationRecord
delegate :dashboard_timezone, to: :metrics_setting, allow_nil: true, prefix: true delegate :dashboard_timezone, to: :metrics_setting, allow_nil: true, prefix: true
delegate :default_git_depth, :default_git_depth=, to: :ci_cd_settings, prefix: :ci delegate :default_git_depth, :default_git_depth=, to: :ci_cd_settings, prefix: :ci
delegate :forward_deployment_enabled, :forward_deployment_enabled=, :forward_deployment_enabled?, to: :ci_cd_settings, prefix: :ci delegate :forward_deployment_enabled, :forward_deployment_enabled=, :forward_deployment_enabled?, to: :ci_cd_settings, prefix: :ci
delegate :job_token_scope_enabled, :job_token_scope_enabled=, :job_token_scope_enabled?, to: :ci_cd_settings, prefix: :ci
delegate :keep_latest_artifact, :keep_latest_artifact=, :keep_latest_artifact?, :keep_latest_artifacts_available?, to: :ci_cd_settings delegate :keep_latest_artifact, :keep_latest_artifact=, :keep_latest_artifact?, :keep_latest_artifacts_available?, to: :ci_cd_settings
delegate :restrict_user_defined_variables, :restrict_user_defined_variables=, :restrict_user_defined_variables?, delegate :restrict_user_defined_variables, :restrict_user_defined_variables=, :restrict_user_defined_variables?,
to: :ci_cd_settings to: :ci_cd_settings
......
...@@ -16,6 +16,7 @@ class ProjectCiCdSetting < ApplicationRecord ...@@ -16,6 +16,7 @@ class ProjectCiCdSetting < ApplicationRecord
allow_nil: true allow_nil: true
default_value_for :forward_deployment_enabled, true default_value_for :forward_deployment_enabled, true
default_value_for :job_token_scope_enabled, true
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)
......
...@@ -99,10 +99,6 @@ class User < ApplicationRecord ...@@ -99,10 +99,6 @@ class User < ApplicationRecord
# Virtual attribute for impersonator # Virtual attribute for impersonator
attr_accessor :impersonator attr_accessor :impersonator
# This attribute hosts a Ci::JobToken::Scope object which is set when
# the user is authenticated successfully via CI_JOB_TOKEN.
attr_accessor :ci_job_token_scope
# #
# Relations # Relations
# #
......
# frozen_string_literal: true
class CreateCiJobTokenScopeLinks < ActiveRecord::Migration[6.0]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
unless table_exists?(:ci_job_token_scope_links)
with_lock_retries do
create_table :ci_job_token_scope_links do |t|
t.belongs_to :source_project, null: false, foreign_key: { to_table: :projects, on_delete: :cascade }
t.belongs_to :target_project, null: false, foreign_key: { to_table: :projects, on_delete: :cascade }
t.belongs_to :added_by, foreign_key: { to_table: :users, on_delete: :nullify }
t.datetime_with_timezone :created_at, null: false
t.index [:source_project_id, :target_project_id], unique: true, name: 'i_ci_job_token_scope_links_on_source_and_target_project'
end
end
end
end
def down
with_lock_retries do
drop_table :ci_job_token_scope_links
end
end
end
# frozen_string_literal: true
class AddJobTokenScopeEnabledToCiCdSettings < ActiveRecord::Migration[6.0]
include Gitlab::Database::MigrationHelpers
def up
with_lock_retries do
add_column :project_ci_cd_settings, :job_token_scope_enabled, :boolean, default: false, null: false
end
end
def down
with_lock_retries do
remove_column :project_ci_cd_settings, :job_token_scope_enabled
end
end
end
dd6bf6ae4988e8e07247388554992d5100dedb2bd66e92c42a6bb144dc6b1937
\ No newline at end of file
...@@ -16561,7 +16561,8 @@ CREATE TABLE project_ci_cd_settings ( ...@@ -16561,7 +16561,8 @@ CREATE TABLE project_ci_cd_settings (
merge_trains_enabled boolean DEFAULT false, merge_trains_enabled boolean DEFAULT false,
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
); );
CREATE SEQUENCE project_ci_cd_settings_id_seq CREATE SEQUENCE project_ci_cd_settings_id_seq
...@@ -27161,9 +27162,6 @@ ALTER TABLE ONLY operations_feature_flag_scopes ...@@ -27161,9 +27162,6 @@ ALTER TABLE ONLY operations_feature_flag_scopes
ALTER TABLE ONLY packages_helm_file_metadata ALTER TABLE ONLY packages_helm_file_metadata
ADD CONSTRAINT fk_rails_a559865345 FOREIGN KEY (package_file_id) REFERENCES packages_package_files(id) ON DELETE CASCADE; ADD CONSTRAINT fk_rails_a559865345 FOREIGN KEY (package_file_id) REFERENCES packages_package_files(id) ON DELETE CASCADE;
ALTER TABLE ONLY ci_job_token_scope_links
ADD CONSTRAINT fk_rails_a562b502cf FOREIGN KEY (added_by_id) REFERENCES users(id) ON DELETE SET NULL;
ALTER TABLE ONLY cluster_projects ALTER TABLE ONLY cluster_projects
ADD CONSTRAINT fk_rails_a5a958bca1 FOREIGN KEY (cluster_id) REFERENCES clusters(id) ON DELETE CASCADE; ADD CONSTRAINT fk_rails_a5a958bca1 FOREIGN KEY (cluster_id) REFERENCES clusters(id) ON DELETE CASCADE;
...@@ -27455,9 +27453,6 @@ ALTER TABLE ONLY ci_running_builds ...@@ -27455,9 +27453,6 @@ ALTER TABLE ONLY ci_running_builds
ALTER TABLE ONLY jira_imports ALTER TABLE ONLY jira_imports
ADD CONSTRAINT fk_rails_da617096ce FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE SET NULL; ADD CONSTRAINT fk_rails_da617096ce FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE SET NULL;
ALTER TABLE ONLY ci_job_token_scope_links
ADD CONSTRAINT fk_rails_dae96135e0 FOREIGN KEY (target_project_id) REFERENCES projects(id) ON DELETE CASCADE;
ALTER TABLE ONLY dependency_proxy_blobs ALTER TABLE ONLY dependency_proxy_blobs
ADD CONSTRAINT fk_rails_db58bbc5d7 FOREIGN KEY (group_id) REFERENCES namespaces(id) ON DELETE CASCADE; ADD CONSTRAINT fk_rails_db58bbc5d7 FOREIGN KEY (group_id) REFERENCES namespaces(id) ON DELETE CASCADE;
...@@ -95,6 +95,7 @@ module API ...@@ -95,6 +95,7 @@ module API
expose :runners_token, if: lambda { |_project, options| options[:user_can_admin_project] } expose :runners_token, if: lambda { |_project, options| options[:user_can_admin_project] }
expose :ci_default_git_depth expose :ci_default_git_depth
expose :ci_forward_deployment_enabled expose :ci_forward_deployment_enabled
expose :ci_job_token_scope_enabled
expose :public_builds, as: :public_jobs expose :public_builds, as: :public_jobs
expose :build_git_strategy, if: lambda { |project, options| options[:user_can_admin_project] } do |project, options| expose :build_git_strategy, if: lambda { |project, options| options[:user_can_admin_project] } do |project, options|
project.build_allow_git_fetch ? 'fetch' : 'clone' project.build_allow_git_fetch ? 'fetch' : 'clone'
......
# frozen_string_literal: true
FactoryBot.define do
factory :ci_job_token_scope_link, class: 'Ci::JobToken::ScopeLink' do
source_project factory: :project
target_project factory: :project
added_by factory: :user
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Ci::JobToken::ScopeLink do
it { is_expected.to belong_to(:source_project) }
it { is_expected.to belong_to(:target_project) }
it { is_expected.to belong_to(:added_by) }
describe 'unique index' do
let!(:link) { create(:ci_job_token_scope_link) }
it 'raises an error' do
expect do
create(:ci_job_token_scope_link, link.attributes)
end.to raise_error(ActiveRecord::RecordNotUnique)
end
end
describe '.from_project' do
let(:project) { create(:project) }
subject { described_class.from_project(project) }
let!(:source_link) { create(:ci_job_token_scope_link, source_project: project) }
let!(:target_link) { create(:ci_job_token_scope_link, target_project: project) }
it 'returns only the links having the given source project' do
expect(subject).to contain_exactly(source_link)
end
end
describe '.to_project' do
let(:project) { create(:project) }
subject { described_class.to_project(project) }
let!(:source_link) { create(:ci_job_token_scope_link, source_project: project) }
let!(:target_link) { create(:ci_job_token_scope_link, target_project: project) }
it 'returns only the links having the given target project' do
expect(subject).to contain_exactly(target_link)
end
end
end
...@@ -50,6 +50,16 @@ RSpec.describe Ci::JobToken::Scope do ...@@ -50,6 +50,16 @@ RSpec.describe Ci::JobToken::Scope do
let(:target_project) { scope_link.target_project } let(:target_project) { scope_link.target_project }
it { is_expected.to be_falsey } it { is_expected.to be_falsey }
context 'when project scope setting is disabled' do
before do
project.ci_job_token_scope_enabled = false
end
it 'considers any project to be part of the scope' do
expect(subject).to be_truthy
end
end
end end
end end
end end
...@@ -21,6 +21,12 @@ RSpec.describe ProjectCiCdSetting do ...@@ -21,6 +21,12 @@ RSpec.describe ProjectCiCdSetting do
end end
end end
describe '#job_token_scope_enabled' do
it 'is true by default' do
expect(described_class.new.job_token_scope_enabled).to be_truthy
end
end
describe '#default_git_depth' do describe '#default_git_depth' do
let(:default_value) { described_class::DEFAULT_GIT_DEPTH } let(:default_value) { described_class::DEFAULT_GIT_DEPTH }
......
...@@ -94,6 +94,7 @@ ci_cd_settings: ...@@ -94,6 +94,7 @@ ci_cd_settings:
remapped_attributes: remapped_attributes:
default_git_depth: ci_default_git_depth default_git_depth: ci_default_git_depth
forward_deployment_enabled: ci_forward_deployment_enabled forward_deployment_enabled: ci_forward_deployment_enabled
job_token_scope_enabled: ci_job_token_scope_enabled
build_import_state: # import_state build_import_state: # import_state
unexposed_attributes: unexposed_attributes:
......
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