Commit 758a6c31 authored by Michael Kozono's avatar Michael Kozono

Merge branch 'fix_compliance_framework_list_api' into 'master'

Fix Namespace list API for compliance framework

See merge request gitlab-org/gitlab!55117
parents fe676e7b 95654e7f
...@@ -57,12 +57,8 @@ module EE ...@@ -57,12 +57,8 @@ module EE
field :compliance_frameworks, field :compliance_frameworks,
::Types::ComplianceManagement::ComplianceFrameworkType.connection_type, ::Types::ComplianceManagement::ComplianceFrameworkType.connection_type,
null: true, null: true,
description: 'Compliance frameworks available to projects in this namespace.', description: 'Compliance frameworks available to projects in this namespace. Available only when feature flag `ff_custom_compliance_frameworks` is enabled.',
feature_flag: :ff_custom_compliance_frameworks do resolver: ::Resolvers::ComplianceManagement::FrameworkResolver
argument :id, ::Types::GlobalIDType[::ComplianceManagement::Framework],
description: 'Global ID of a specific compliance framework to return.',
required: false
end
def additional_purchased_storage_size def additional_purchased_storage_size
object.additional_purchased_storage_size.megabytes object.additional_purchased_storage_size.megabytes
...@@ -71,26 +67,6 @@ module EE ...@@ -71,26 +67,6 @@ module EE
def storage_size_limit def storage_size_limit
object.root_storage_size.limit object.root_storage_size.limit
end end
def compliance_frameworks(id: nil)
id = ::Types::GlobalIDType[::ComplianceManagement::Framework].coerce_isolated_input(id) unless id.nil?
BatchLoader::GraphQL
.for([object.id, id&.model_id])
.batch(default_value: []) do |keys, loader|
namespace_ids = keys.map(&:first).uniq
by_namespace_id = keys.group_by(&:first).transform_values { |k| k.map(&:second) }
frameworks = ::ComplianceManagement::Framework.with_namespaces(namespace_ids)
frameworks.group_by(&:namespace_id).each do |ns_id, group|
by_namespace_id[ns_id].each do |fw_id|
group.each do |fw|
next unless fw_id.nil? || fw_id.to_i == fw.id
loader.call([ns_id, fw_id]) { |array| array << fw }
end
end
end
end
end
end end
end end
end end
......
# frozen_string_literal: true
module Resolvers
module ComplianceManagement
class FrameworkResolver < BaseResolver
include Gitlab::Graphql::Authorize::AuthorizeResource
type ::Types::ComplianceManagement::ComplianceFrameworkType.connection_type, null: true
argument :id, ::Types::GlobalIDType[::ComplianceManagement::Framework],
description: 'Global ID of a specific compliance framework to return.',
required: false
def resolve(id: nil)
# TODO: remove this line when the compatibility layer is removed
# See: https://gitlab.com/gitlab-org/gitlab/-/issues/257883
id = ::Types::GlobalIDType[::ComplianceManagement::Framework].coerce_isolated_input(id) unless id.nil?
BatchLoader::GraphQL
.for([object.id, id&.model_id])
.batch(default_value: []) do |keys, loader|
namespace_ids = keys.map(&:first).uniq
by_namespace_id = keys.group_by(&:first).transform_values { |k| k.map(&:second) }
evaluate(namespace_ids, by_namespace_id, loader)
end
end
private
def evaluate(namespace_ids, by_namespace_id, loader)
frameworks(namespace_ids).group_by(&:namespace_id).each do |ns_id, group|
by_namespace_id[ns_id].each do |fw_id|
authorize!
group.each do |fw|
next unless fw_id.nil? || fw_id.to_i == fw.id
loader.call([ns_id, fw_id]) { |array| array << fw }
end
end
end
end
def frameworks(namespace_ids)
::ComplianceManagement::Framework.with_namespaces(namespace_ids)
end
def authorize!
Ability.allowed?(context[:current_user], :admin_compliance_framework, object) || raise_resource_not_available_error!
end
end
end
end
...@@ -6,12 +6,17 @@ module EE ...@@ -6,12 +6,17 @@ module EE
prepended do prepended do
condition(:over_storage_limit, scope: :subject) { @subject.over_storage_limit? } condition(:over_storage_limit, scope: :subject) { @subject.over_storage_limit? }
condition(:compliance_framework_available) do
@subject.feature_available?(:custom_compliance_frameworks) &&
::Feature.enabled?(:ff_custom_compliance_frameworks, @subject)
end
rule { admin & is_gitlab_com }.enable :update_subscription_limit rule { admin & is_gitlab_com }.enable :update_subscription_limit
rule { over_storage_limit }.policy do rule { over_storage_limit }.policy do
prevent :create_projects prevent :create_projects
end end
rule { can?(:owner_access) & compliance_framework_available }.enable :admin_compliance_framework
end end
end end
end end
...@@ -5,6 +5,7 @@ require 'spec_helper' ...@@ -5,6 +5,7 @@ require 'spec_helper'
RSpec.describe NamespacePolicy do RSpec.describe NamespacePolicy do
let(:owner) { build_stubbed(:user) } let(:owner) { build_stubbed(:user) }
let(:namespace) { build_stubbed(:namespace, owner: owner) } let(:namespace) { build_stubbed(:namespace, owner: owner) }
let(:admin) { build_stubbed(:admin) }
let(:owner_permissions) { [:create_projects, :admin_namespace, :read_namespace] } let(:owner_permissions) { [:create_projects, :admin_namespace, :read_namespace] }
subject { described_class.new(current_user, namespace) } subject { described_class.new(current_user, namespace) }
...@@ -43,5 +44,53 @@ RSpec.describe NamespacePolicy do ...@@ -43,5 +44,53 @@ RSpec.describe NamespacePolicy do
end end
end end
context ':admin_compliance_framework' do
shared_examples 'permitted' do
it { is_expected.to(be_allowed(:admin_compliance_framework)) }
end
shared_examples 'not permitted' do
it { is_expected.to(be_disallowed(:admin_compliance_framework)) }
end
context 'when feature is available' do
before do
stub_licensed_features(custom_compliance_frameworks: true)
stub_feature_flags(ff_custom_compliance_frameworks: true)
end
context 'when user is admin', :enable_admin_mode do
let(:current_user) { admin }
it_behaves_like 'permitted'
end
context 'when user is owner' do
let(:current_user) { owner }
it_behaves_like 'permitted'
end
end
context 'when feature is not available' do
before do
stub_licensed_features(custom_compliance_frameworks: false)
stub_feature_flags(ff_custom_compliance_frameworks: false)
end
context 'when user is admin', :enable_admin_mode do
let(:current_user) { admin }
it_behaves_like 'not permitted'
end
context 'when user is owner' do
let(:current_user) { owner }
it_behaves_like 'not permitted'
end
end
end
it_behaves_like 'update namespace limit policy' it_behaves_like 'update namespace limit policy'
end end
...@@ -17,6 +17,11 @@ RSpec.describe 'getting a list of compliance frameworks for a root namespace' do ...@@ -17,6 +17,11 @@ RSpec.describe 'getting a list of compliance frameworks for a root namespace' do
end end
context 'when authenticated as the namespace owner' do context 'when authenticated as the namespace owner' do
before do
stub_licensed_features(custom_compliance_frameworks: true)
stub_feature_flags(ff_custom_compliance_frameworks: true)
end
let(:current_user) { namespace.owner } let(:current_user) { namespace.owner }
it 'returns the groups compliance frameworks' do it 'returns the groups compliance frameworks' do
...@@ -120,7 +125,7 @@ RSpec.describe 'getting a list of compliance frameworks for a root namespace' do ...@@ -120,7 +125,7 @@ RSpec.describe 'getting a list of compliance frameworks for a root namespace' do
it 'responds with error when querying a compliance framework' do it 'responds with error when querying a compliance framework' do
post_graphql(query, current_user: current_user) post_graphql(query, current_user: current_user)
expect(graphql_errors).to contain_exactly(include('message' => "Field 'complianceFrameworks' doesn't exist on type 'Namespace'")) expect(graphql_errors).to contain_exactly(include('message' => "The resource that you are attempting to access does not exist or you don't have permission to perform this action"))
end end
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