Commit f7aae684 authored by Steve Abrams's avatar Steve Abrams

Merge branch 'add-licensed-agent-ci-tunnel-feature-guards' into 'master'

Add License checks to AgentAuthorizationsFinder

See merge request gitlab-org/gitlab!73226
parents 1631b270 89dc20ad
...@@ -31,6 +31,7 @@ module Clusters ...@@ -31,6 +31,7 @@ module Clusters
.joins(agent: :project) .joins(agent: :project)
.preload(agent: :project) .preload(agent: :project)
.where(cluster_agents: { projects: { namespace_id: ancestor_ids } }) .where(cluster_agents: { projects: { namespace_id: ancestor_ids } })
.with_available_ci_access_fields(project)
.to_a .to_a
end end
...@@ -53,6 +54,7 @@ module Clusters ...@@ -53,6 +54,7 @@ module Clusters
.joins(cte_join_sources) .joins(cte_join_sources)
.joins(agent: :project) .joins(agent: :project)
.where('projects.namespace_id IN (SELECT id FROM ordered_ancestors)') .where('projects.namespace_id IN (SELECT id FROM ordered_ancestors)')
.with_available_ci_access_fields(project)
.order(Arel.sql('agent_id, array_position(ARRAY(SELECT id FROM ordered_ancestors)::bigint[], agent_group_authorizations.group_id)')) .order(Arel.sql('agent_id, array_position(ARRAY(SELECT id FROM ordered_ancestors)::bigint[], agent_group_authorizations.group_id)'))
.select('DISTINCT ON (agent_id) agent_group_authorizations.*') .select('DISTINCT ON (agent_id) agent_group_authorizations.*')
.preload(agent: :project) .preload(agent: :project)
......
...@@ -3,6 +3,8 @@ ...@@ -3,6 +3,8 @@
module Clusters module Clusters
module Agents module Agents
class GroupAuthorization < ApplicationRecord class GroupAuthorization < ApplicationRecord
include ::Clusters::Agents::AuthorizationConfigScopes
self.table_name = 'agent_group_authorizations' self.table_name = 'agent_group_authorizations'
belongs_to :agent, class_name: 'Clusters::Agent', optional: false belongs_to :agent, class_name: 'Clusters::Agent', optional: false
......
...@@ -3,6 +3,8 @@ ...@@ -3,6 +3,8 @@
module Clusters module Clusters
module Agents module Agents
class ProjectAuthorization < ApplicationRecord class ProjectAuthorization < ApplicationRecord
include ::Clusters::Agents::AuthorizationConfigScopes
self.table_name = 'agent_project_authorizations' self.table_name = 'agent_project_authorizations'
belongs_to :agent, class_name: 'Clusters::Agent', optional: false belongs_to :agent, class_name: 'Clusters::Agent', optional: false
......
# frozen_string_literal: true
module Clusters
module Agents
module AuthorizationConfigScopes
extend ActiveSupport::Concern
included do
scope :with_available_ci_access_fields, ->(project) {
where("config->'access_as' IS NULL")
.or(where("config->'access_as' = '{}'"))
.or(where("config->'access_as' ?| array[:fields]", fields: available_ci_access_fields(project)))
}
end
class_methods do
def available_ci_access_fields(_project)
%w(agent)
end
end
end
end
end
Clusters::Agents::AuthorizationConfigScopes.prepend_mod
# frozen_string_literal: true
module EE
module Clusters
module Agents
module AuthorizationConfigScopes
extend ActiveSupport::Concern
prepended do
class_methods do
alias_method :base_available_ci_access_fields, :available_ci_access_fields
def available_ci_access_fields(project)
base_available_ci_access_fields(project).tap do |fields|
if project.licensed_feature_available?(:cluster_agents_ci_impersonation)
fields << "ci_job"
fields << "ci_user"
fields << "impersonate"
end
end
end
end
end
end
end
end
end
...@@ -68,6 +68,7 @@ class License < ApplicationRecord ...@@ -68,6 +68,7 @@ class License < ApplicationRecord
ci_cd_projects ci_cd_projects
ci_secrets_management ci_secrets_management
cluster_agents_gitops cluster_agents_gitops
cluster_agents_ci_impersonation
cluster_deployments cluster_deployments
code_owner_approval_required code_owner_approval_required
commit_committer_check commit_committer_check
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Clusters::AgentAuthorizationsFinder do
describe '#execute' do
let_it_be(:top_level_group) { create(:group) }
let_it_be(:agent_configuration_project) { create(:project, namespace: top_level_group) }
let_it_be(:bottom_level_group) { create(:group, parent: top_level_group) }
let_it_be(:requesting_project, reload: true) { create(:project, namespace: bottom_level_group) }
let_it_be(:production_agent) { create(:cluster_agent, project: agent_configuration_project) }
subject { described_class.new(requesting_project).execute }
shared_examples_for 'licensed access_as' do
context 'impersonate' do
let(:config) { { access_as: { impersonate: {} } } }
it { is_expected.to be_empty }
context 'when available' do
before do
stub_licensed_features(cluster_agents_ci_impersonation: true)
end
it { is_expected.to match_array [authorization] }
end
end
context 'ci_user' do
let(:config) { { access_as: { ci_user: {} } } }
it { is_expected.to be_empty }
context 'when available' do
before do
stub_licensed_features(cluster_agents_ci_impersonation: true)
end
it { is_expected.to match_array [authorization] }
end
end
context 'ci_job' do
let(:config) { { access_as: { ci_job: {} } } }
it { is_expected.to be_empty }
context 'when available' do
before do
stub_licensed_features(cluster_agents_ci_impersonation: true)
end
it { is_expected.to match_array [authorization] }
end
end
end
describe 'project authorizations' do
it_behaves_like 'licensed access_as' do
let!(:authorization) do
create(
:agent_project_authorization,
agent: production_agent,
project: requesting_project,
config: config
)
end
end
end
describe 'group authorizations' do
it_behaves_like 'licensed access_as' do
let!(:authorization) do
create(
:agent_group_authorization,
agent: production_agent,
group: top_level_group,
config: config
)
end
end
end
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe EE::Clusters::Agents::AuthorizationConfigScopes do
describe '.with_available_ci_access_fields' do
let_it_be(:project) { create(:project) }
let_it_be(:agent_authorization_0) { create(:agent_project_authorization, project: project) }
let_it_be(:agent_authorization_1) { create(:agent_project_authorization, project: project, config: { access_as: {} }) }
let_it_be(:agent_authorization_2) { create(:agent_project_authorization, project: project, config: { access_as: { agent: {} } }) }
let_it_be(:impersonate_authorization) { create(:agent_project_authorization, project: project, config: { access_as: { impersonate: {} } }) }
let_it_be(:ci_user_authorization) { create(:agent_project_authorization, project: project, config: { access_as: { ci_user: {} } }) }
let_it_be(:ci_job_authorization) { create(:agent_project_authorization, project: project, config: { access_as: { ci_job: {} } }) }
subject { Clusters::Agents::ProjectAuthorization.with_available_ci_access_fields(project) }
it { is_expected.not_to include(ci_job_authorization)}
it { is_expected.not_to include(ci_user_authorization)}
it { is_expected.not_to include(impersonate_authorization)}
context 'with :cluster_agents_ci_impersonation' do
before do
stub_licensed_features(cluster_agents_ci_impersonation: true)
end
it { is_expected.to include(ci_job_authorization, ci_user_authorization, impersonate_authorization) }
end
end
end
...@@ -17,6 +17,34 @@ RSpec.describe Clusters::AgentAuthorizationsFinder do ...@@ -17,6 +17,34 @@ RSpec.describe Clusters::AgentAuthorizationsFinder do
subject { described_class.new(requesting_project).execute } subject { described_class.new(requesting_project).execute }
shared_examples_for 'access_as' do
let(:config) { { access_as: { access_as => {} } } }
context 'agent' do
let(:access_as) { :agent }
it { is_expected.to match_array [authorization] }
end
context 'impersonate' do
let(:access_as) { :impersonate }
it { is_expected.to be_empty }
end
context 'ci_user' do
let(:access_as) { :ci_user }
it { is_expected.to be_empty }
end
context 'ci_job' do
let(:access_as) { :ci_job }
it { is_expected.to be_empty }
end
end
describe 'project authorizations' do describe 'project authorizations' do
context 'agent configuration project does not share a root namespace with the given project' do context 'agent configuration project does not share a root namespace with the given project' do
let(:unrelated_agent) { create(:cluster_agent) } let(:unrelated_agent) { create(:cluster_agent) }
...@@ -29,7 +57,7 @@ RSpec.describe Clusters::AgentAuthorizationsFinder do ...@@ -29,7 +57,7 @@ RSpec.describe Clusters::AgentAuthorizationsFinder do
end end
context 'with project authorizations present' do context 'with project authorizations present' do
let!(:authorization) {create(:agent_project_authorization, agent: production_agent, project: requesting_project) } let!(:authorization) { create(:agent_project_authorization, agent: production_agent, project: requesting_project) }
it { is_expected.to match_array [authorization] } it { is_expected.to match_array [authorization] }
end end
...@@ -41,6 +69,10 @@ RSpec.describe Clusters::AgentAuthorizationsFinder do ...@@ -41,6 +69,10 @@ RSpec.describe Clusters::AgentAuthorizationsFinder do
it { is_expected.to match_array [project_authorization] } it { is_expected.to match_array [project_authorization] }
end end
it_behaves_like 'access_as' do
let!(:authorization) { create(:agent_project_authorization, agent: production_agent, project: requesting_project, config: config) }
end
end end
describe 'implicit authorizations' do describe 'implicit authorizations' do
...@@ -83,6 +115,10 @@ RSpec.describe Clusters::AgentAuthorizationsFinder do ...@@ -83,6 +115,10 @@ RSpec.describe Clusters::AgentAuthorizationsFinder do
expect(subject).to contain_exactly(bottom_level_auth) expect(subject).to contain_exactly(bottom_level_auth)
end end
end end
it_behaves_like 'access_as' do
let!(:authorization) { create(:agent_group_authorization, agent: production_agent, group: top_level_group, config: config) }
end
end end
end end
end end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Clusters::Agents::AuthorizationConfigScopes do
describe '.with_available_ci_access_fields' do
let(:project) { create(:project) }
let!(:agent_authorization_0) { create(:agent_project_authorization, project: project) }
let!(:agent_authorization_1) { create(:agent_project_authorization, project: project, config: { access_as: {} }) }
let!(:agent_authorization_2) { create(:agent_project_authorization, project: project, config: { access_as: { agent: {} } }) }
let!(:impersonate_authorization) { create(:agent_project_authorization, project: project, config: { access_as: { impersonate: {} } }) }
let!(:ci_user_authorization) { create(:agent_project_authorization, project: project, config: { access_as: { ci_user: {} } }) }
let!(:ci_job_authorization) { create(:agent_project_authorization, project: project, config: { access_as: { ci_job: {} } }) }
let!(:unexpected_authorization) { create(:agent_project_authorization, project: project, config: { access_as: { unexpected: {} } }) }
subject { Clusters::Agents::ProjectAuthorization.with_available_ci_access_fields(project) }
it { is_expected.to contain_exactly(agent_authorization_0, agent_authorization_1, agent_authorization_2) }
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