summaryrefslogtreecommitdiff
path: root/spec/lib/gitlab/graphql/authorize/authorize_field_service_spec.rb
diff options
context:
space:
mode:
Diffstat (limited to 'spec/lib/gitlab/graphql/authorize/authorize_field_service_spec.rb')
-rw-r--r--spec/lib/gitlab/graphql/authorize/authorize_field_service_spec.rb132
1 files changed, 132 insertions, 0 deletions
diff --git a/spec/lib/gitlab/graphql/authorize/authorize_field_service_spec.rb b/spec/lib/gitlab/graphql/authorize/authorize_field_service_spec.rb
new file mode 100644
index 00000000000..aec9c4baf0a
--- /dev/null
+++ b/spec/lib/gitlab/graphql/authorize/authorize_field_service_spec.rb
@@ -0,0 +1,132 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+# Also see spec/graphql/features/authorization_spec.rb for
+# integration tests of AuthorizeFieldService
+describe Gitlab::Graphql::Authorize::AuthorizeFieldService do
+ def type(type_authorizations = [])
+ Class.new(Types::BaseObject) do
+ graphql_name "TestType"
+
+ authorize type_authorizations
+ end
+ end
+
+ def type_with_field(field_type, field_authorizations = [], resolved_value = "Resolved value")
+ Class.new(Types::BaseObject) do
+ graphql_name "TestTypeWithField"
+ field :test_field, field_type, null: true, authorize: field_authorizations, resolve: -> (_, _, _) { resolved_value}
+ end
+ end
+
+ let(:current_user) { double(:current_user) }
+ subject(:service) { described_class.new(field) }
+
+ describe "#authorized_resolve" do
+ let(:presented_object) { double("presented object") }
+ let(:presented_type) { double("parent type", object: presented_object) }
+ subject(:resolved) { service.authorized_resolve.call(presented_type, {}, { current_user: current_user }) }
+
+ context "scalar types" do
+ shared_examples "checking permissions on the presented object" do
+ it "checks the abilities on the object being presented and returns the value" do
+ expected_permissions.each do |permission|
+ spy_ability_check_for(permission, presented_object, passed: true)
+ end
+
+ expect(resolved).to eq("Resolved value")
+ end
+
+ it "returns nil if the value wasn't authorized" do
+ allow(Ability).to receive(:allowed?).and_return false
+
+ expect(resolved).to be_nil
+ end
+ end
+
+ context "when the field is a built-in scalar type" do
+ let(:field) { type_with_field(GraphQL::STRING_TYPE, :read_field).fields["testField"].to_graphql }
+ let(:expected_permissions) { [:read_field] }
+
+ it_behaves_like "checking permissions on the presented object"
+ end
+
+ context "when the field is a list of scalar types" do
+ let(:field) { type_with_field([GraphQL::STRING_TYPE], :read_field).fields["testField"].to_graphql }
+ let(:expected_permissions) { [:read_field] }
+
+ it_behaves_like "checking permissions on the presented object"
+ end
+
+ context "when the field is sub-classed scalar type" do
+ let(:field) { type_with_field(Types::TimeType, :read_field).fields["testField"].to_graphql }
+ let(:expected_permissions) { [:read_field] }
+
+ it_behaves_like "checking permissions on the presented object"
+ end
+
+ context "when the field is a list of sub-classed scalar types" do
+ let(:field) { type_with_field([Types::TimeType], :read_field).fields["testField"].to_graphql }
+ let(:expected_permissions) { [:read_field] }
+
+ it_behaves_like "checking permissions on the presented object"
+ end
+ end
+
+ context "when the field is a specific type" do
+ let(:custom_type) { type(:read_type) }
+ let(:object_in_field) { double("presented in field") }
+ let(:field) { type_with_field(custom_type, :read_field, object_in_field).fields["testField"].to_graphql }
+
+ it "checks both field & type permissions" do
+ spy_ability_check_for(:read_field, object_in_field, passed: true)
+ spy_ability_check_for(:read_type, object_in_field, passed: true)
+
+ expect(resolved).to eq(object_in_field)
+ end
+
+ it "returns nil if viewing was not allowed" do
+ spy_ability_check_for(:read_field, object_in_field, passed: false)
+ spy_ability_check_for(:read_type, object_in_field, passed: true)
+
+ expect(resolved).to be_nil
+ end
+
+ context "when the field is a list" do
+ let(:object_1) { double("presented in field 1") }
+ let(:object_2) { double("presented in field 2") }
+ let(:presented_types) { [double(object: object_1), double(object: object_2)] }
+ let(:field) { type_with_field([custom_type], :read_field, presented_types).fields["testField"].to_graphql }
+
+ it "checks all permissions" do
+ allow(Ability).to receive(:allowed?) { true }
+
+ spy_ability_check_for(:read_field, object_1, passed: true)
+ spy_ability_check_for(:read_type, object_1, passed: true)
+ spy_ability_check_for(:read_field, object_2, passed: true)
+ spy_ability_check_for(:read_type, object_2, passed: true)
+
+ expect(resolved).to eq(presented_types)
+ end
+
+ it "filters out objects that the user cannot see" do
+ allow(Ability).to receive(:allowed?) { true }
+
+ spy_ability_check_for(:read_type, object_1, passed: false)
+
+ expect(resolved.map(&:object)).to contain_exactly(object_2)
+ end
+ end
+ end
+ end
+
+ private
+
+ def spy_ability_check_for(ability, object, passed: true)
+ expect(Ability)
+ .to receive(:allowed?)
+ .with(current_user, ability, object)
+ .and_return(passed)
+ end
+end