Skip to content

Commit

Permalink
Merge c92ccb8 into 71dc649
Browse files Browse the repository at this point in the history
  • Loading branch information
exAspArk committed Jun 29, 2018
2 parents 71dc649 + c92ccb8 commit c8341d4
Show file tree
Hide file tree
Showing 11 changed files with 153 additions and 65 deletions.
6 changes: 6 additions & 0 deletions .travis.yml
Expand Up @@ -5,3 +5,9 @@ rvm:
env:
- CI=true
before_install: gem install bundler -v 1.15.2
matrix:
include:
- gemfile: graphql-1.7.gemfile
env: GRAPHQL_RUBY_VERSION=1_7
- gemfile: graphql-1.8.gemfile
env: GRAPHQL_RUBY_VERSION=1_8
5 changes: 2 additions & 3 deletions Gemfile
@@ -1,9 +1,8 @@
source "https://rubygems.org"

git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }

gem "pry"
gem 'coveralls', require: false

gem "graphql", "~> 1.8.4"

# Specify your gem's dependencies in graphql-guard.gemspec
gemspec
8 changes: 8 additions & 0 deletions graphql-1.7.gemfile
@@ -0,0 +1,8 @@
source "https://rubygems.org"

gem "pry"
gem 'coveralls'

gem "graphql", "~> 1.7.14"

gemspec
8 changes: 8 additions & 0 deletions graphql-1.8.gemfile
@@ -0,0 +1,8 @@
source "https://rubygems.org"

gem "pry"
gem 'coveralls'

gem "graphql", "~> 1.8.4"

gemspec
16 changes: 12 additions & 4 deletions lib/graphql/guard.rb
Expand Up @@ -3,10 +3,6 @@
require "graphql"
require "graphql/guard/version"

GraphQL::ObjectType.accepts_definitions(guard: GraphQL::Define.assign_metadata_key(:guard))
GraphQL::Field.accepts_definitions(guard: GraphQL::Define.assign_metadata_key(:guard))
GraphQL::Field.accepts_definitions(mask: GraphQL::Define.assign_metadata_key(:mask))

module GraphQL
class Guard
ANY_FIELD_NAME = :'*'
Expand Down Expand Up @@ -72,3 +68,15 @@ def inline_type_guard(type)
end
end
end

if GraphQL::ObjectType.respond_to?(:accepts_definitions) # GraphQL-Ruby version < 1.8
GraphQL::ObjectType.accepts_definitions(guard: GraphQL::Define.assign_metadata_key(:guard))
GraphQL::Field.accepts_definitions(guard: GraphQL::Define.assign_metadata_key(:guard))
GraphQL::Field.accepts_definitions(mask: GraphQL::Define.assign_metadata_key(:mask))
end

if GraphQL::Schema::Object.respond_to?(:accepts_definition) # GraphQL-Ruby version >= 1.8
GraphQL::Schema::Object.accepts_definition(:guard)
GraphQL::Schema::Field.accepts_definition(:guard)
GraphQL::Schema::Field.accepts_definition(:mask)
end
14 changes: 14 additions & 0 deletions lib/graphql/guard/testing.rb
Expand Up @@ -33,4 +33,18 @@ def field_with_guard(field_name, policy_object = nil)
end
end
end

class Schema
class Object
def self.field_with_guard(field_name, policy_object = nil)
field = fields[field_name]
return unless field

field.to_graphql.clone.tap do |f|
f.__policy_object = policy_object
f.__guard_type = self.to_graphql
end
end
end
end
end
93 changes: 67 additions & 26 deletions spec/fixtures/inline_schema.rb
@@ -1,37 +1,78 @@
# frozen_string_literal: true

module Inline
PostType = GraphQL::ObjectType.define do
name "Post"
guard ->(_post, _args, ctx) { ctx[:current_user].admin? }
field :id, !types.ID
field :title, types.String
end
case ENV['GRAPHQL_RUBY_VERSION']
when '1_7'
PostType = GraphQL::ObjectType.define do
name "Post"
guard ->(_post, _args, ctx) { ctx[:current_user].admin? }
field :id, !types.ID
field :title, types.String
end

QueryType = GraphQL::ObjectType.define do
name "Query"
field :posts, !types[!PostType] do
argument :user_id, !types.ID
guard ->(_obj, args, ctx) { args[:user_id] == ctx[:current_user].id }
resolve ->(_obj, args, _ctx) { Post.where(user_id: args[:user_id]) }
QueryType = GraphQL::ObjectType.define do
name "Query"
field :posts, !types[!PostType] do
argument :userId, !types.ID
guard ->(_obj, args, ctx) { args[:userId] == ctx[:current_user].id }
resolve ->(_obj, args, _ctx) { Post.where(user_id: args[:userId]) }
end

field :postsWithMask, !types[!PostType] do
argument :userId, !types.ID
mask ->(ctx) { ctx[:current_user].admin? }
resolve ->(_obj, args, _ctx) { Post.where(user_id: args[:userId]) }
end
end

field :posts_with_mask, !types[!PostType] do
argument :user_id, !types.ID
mask ->(ctx) { ctx[:current_user].admin? }
resolve ->(_obj, args, _ctx) { Post.where(user_id: args[:user_id]) }
Schema = GraphQL::Schema.define do
query QueryType
use GraphQL::Guard.new
end
end

Schema = GraphQL::Schema.define do
query QueryType
use GraphQL::Guard.new
end
SchemaWithoutExceptions = GraphQL::Schema.define do
query QueryType
use GraphQL::Guard.new(not_authorized: ->(type, field) {
GraphQL::ExecutionError.new("Not authorized to access #{type}.#{field}")
})
end
when '1_8'
class PostType < GraphQL::Schema::Object
guard ->(_post, _args, ctx) { ctx[:current_user].admin? }
field :id, ID, null: false
field :title, String, null: true
end

class QueryType < GraphQL::Schema::Object
field :posts, [PostType], null: false do
argument :user_id, ID, required: true
guard ->(_obj, args, ctx) { args[:userId] == ctx[:current_user].id }
end

SchemaWithoutExceptions = GraphQL::Schema.define do
query QueryType
use GraphQL::Guard.new(not_authorized: ->(type, field) {
GraphQL::ExecutionError.new("Not authorized to access #{type}.#{field}")
})
field :posts_with_mask, [PostType], null: false do
argument :user_id, ID, required: true
mask ->(ctx) { ctx[:current_user].admin? }
end

def posts(user_id:)
Post.where(user_id: user_id)
end

def posts_with_mask(user_id:)
Post.where(user_id: user_id)
end
end

class Schema < GraphQL::Schema
query QueryType
use GraphQL::Guard.new
end

class SchemaWithoutExceptions < GraphQL::Schema
query QueryType
use GraphQL::Guard.new(not_authorized: ->(type, field) {
GraphQL::ExecutionError.new("Not authorized to access #{type}.#{field}")
})
end
end
end
6 changes: 3 additions & 3 deletions spec/fixtures/policy_object_schema.rb
Expand Up @@ -10,15 +10,15 @@ module PolicyObject
QueryType = GraphQL::ObjectType.define do
name "Query"
field :posts, !types[!PostType] do
argument :user_id, !types.ID
resolve ->(_obj, args, _ctx) { Post.where(user_id: args[:user_id]) }
argument :userId, !types.ID
resolve ->(_obj, args, _ctx) { Post.where(user_id: args[:userId]) }
end
end

class GraphqlPolicy
RULES = {
QueryType => {
posts: ->(_obj, args, ctx) { args[:user_id] == ctx[:current_user].id }
posts: ->(_obj, args, ctx) { args[:userId] == ctx[:current_user].id }
},
PostType => {
'*': ->(_post, args, ctx) { ctx[:current_user].admin? }
Expand Down
46 changes: 23 additions & 23 deletions spec/graphql/guard_spec.rb
Expand Up @@ -11,40 +11,40 @@
context 'inline guard' do
it 'authorizes to execute a query' do
user = User.new(id: '1', role: 'admin')
query = "query($user_id: ID!) { posts(user_id: $user_id) { id title } }"
query = "query($userId: ID!) { posts(userId: $userId) { id title } }"

result = Inline::Schema.execute(query, variables: {'user_id' => user.id}, context: {current_user: user})
result = Inline::Schema.execute(query, variables: {'userId' => user.id}, context: {current_user: user})

expect(result).to eq({"data" => {"posts" => [{"id" => "1", "title" => "Post Title"}]}})
end

it 'does not authorize a field' do
user = User.new(id: '1', role: 'admin')
query = "query($user_id: ID!) { posts(user_id: $user_id) { id title } }"
query = "query($userId: ID!) { posts(userId: $userId) { id title } }"

expect {
Inline::Schema.execute(query, variables: {'user_id' => '2'}, context: {current_user: user})
Inline::Schema.execute(query, variables: {'userId' => '2'}, context: {current_user: user})
}.to raise_error(GraphQL::Guard::NotAuthorizedError, 'Query.posts')
end

it 'does not authorize a field with a policy on the type' do
user = User.new(id: '1', role: 'not_admin')
query = "query($user_id: ID!) { posts(user_id: $user_id) { id title } }"
query = "query($userId: ID!) { posts(userId: $userId) { id title } }"

expect {
Inline::Schema.execute(query, variables: {'user_id' => '1'}, context: {current_user: user})
Inline::Schema.execute(query, variables: {'userId' => '1'}, context: {current_user: user})
}.to raise_error(GraphQL::Guard::NotAuthorizedError, 'Post.id')
end

it 'does not authorize a field and returns an error' do
user = User.new(id: '1', role: 'not_admin')
query = "query($user_id: ID!) { posts(user_id: $user_id) { id title } }"
query = "query($userId: ID!) { posts(userId: $userId) { id title } }"

result = Inline::SchemaWithoutExceptions.execute(query, variables: {'user_id' => '1'}, context: {current_user: user})
result = Inline::SchemaWithoutExceptions.execute(query, variables: {'userId' => '1'}, context: {current_user: user})

expect(result['errors']).to eq([{
"message" => "Not authorized to access Post.id",
"locations" => [{"line" => 1, "column" => 51}],
"locations" => [{"line" => 1, "column" => 48}],
"path" => ["posts", 0, "id"]}
])
expect(result['data']).to eq(nil)
Expand All @@ -54,52 +54,52 @@
context 'inline mask' do
it 'allows to query a field' do
user = User.new(id: '1', role: 'admin')
query = "query($user_id: ID!) { posts_with_mask(user_id: $user_id) { id } }"
query = "query($userId: ID!) { postsWithMask(userId: $userId) { id } }"

result = Inline::Schema.execute(query, variables: {'user_id' => user.id}, context: {current_user: user})
result = Inline::Schema.execute(query, variables: {'userId' => user.id}, context: {current_user: user})

expect(result.to_h).to eq({"data" => {"posts_with_mask" => [{"id" => "1"}]}})
expect(result.to_h).to eq({"data" => {"postsWithMask" => [{"id" => "1"}]}})
end

it 'hides a field' do
user = User.new(id: '1', role: 'not_admin')
query = "query($user_id: ID!) { posts_with_mask(user_id: $user_id) { id } }"
query = "query($userId: ID!) { postsWithMask(userId: $userId) { id } }"

result = Inline::Schema.execute(query, variables: {'user_id' => user.id}, context: {current_user: user})
result = Inline::Schema.execute(query, variables: {'userId' => user.id}, context: {current_user: user})

expect(result['errors']).to include({
"message" => "Field 'posts_with_mask' doesn't exist on type 'Query'",
"locations" => [{"line" => 1, "column" => 24}],
"fields" => ["query", "posts_with_mask"]
"message" => "Field 'postsWithMask' doesn't exist on type 'Query'",
"locations" => [{"line" => 1, "column" => 23}],
"fields" => ["query", "postsWithMask"]
})
end
end

context 'policy object guard' do
it 'authorizes to execute a query' do
user = User.new(id: '1', role: 'admin')
query = "query($user_id: ID!) { posts(user_id: $user_id) { id title } }"
query = "query($userId: ID!) { posts(userId: $userId) { id title } }"

result = PolicyObject::Schema.execute(query, variables: {'user_id' => user.id}, context: {current_user: user})
result = PolicyObject::Schema.execute(query, variables: {'userId' => user.id}, context: {current_user: user})

expect(result).to eq({"data" => {"posts" => [{"id" => "1", "title" => "Post Title"}]}})
end

it 'does not authorize a field' do
user = User.new(id: '1', role: 'admin')
query = "query($user_id: ID!) { posts(user_id: $user_id) { id title } }"
query = "query($userId: ID!) { posts(userId: $userId) { id title } }"

expect {
PolicyObject::Schema.execute(query, variables: {'user_id' => '2'}, context: {current_user: user})
PolicyObject::Schema.execute(query, variables: {'userId' => '2'}, context: {current_user: user})
}.to raise_error(GraphQL::Guard::NotAuthorizedError, 'Query.posts')
end

it 'does not authorize a field with a policy on the type' do
user = User.new(id: '1', role: 'not_admin')
query = "query($user_id: ID!) { posts(user_id: $user_id) { id title } }"
query = "query($userId: ID!) { posts(userId: $userId) { id title } }"

expect {
PolicyObject::Schema.execute(query, variables: {'user_id' => '1'}, context: {current_user: user})
PolicyObject::Schema.execute(query, variables: {'userId' => '1'}, context: {current_user: user})
}.to raise_error(GraphQL::Guard::NotAuthorizedError, 'Post.id')
end
end
Expand Down
12 changes: 6 additions & 6 deletions spec/graphql/testing_spec.rb
Expand Up @@ -15,7 +15,7 @@
posts_field = Inline::QueryType.field_with_guard('posts')
user = User.new(id: '1', role: 'admin')

result = posts_field.guard(nil, {user_id: user.id}, {current_user: user})
result = posts_field.guard(nil, {userId: user.id}, {current_user: user})

expect(result).to eq(true)
end
Expand All @@ -24,7 +24,7 @@
posts_field = Inline::QueryType.field_with_guard('posts')
user = User.new(id: '1', role: 'admin')

result = posts_field.guard(nil, {user_id: '2'}, {current_user: user})
result = posts_field.guard(nil, {userId: '2'}, {current_user: user})

expect(result).to eq(false)
end
Expand All @@ -44,7 +44,7 @@
posts_field = PolicyObject::QueryType.field_with_guard('posts', PolicyObject::GraphqlPolicy)
user = User.new(id: '1', role: 'admin')

result = posts_field.guard(nil, {user_id: user.id}, {current_user: user})
result = posts_field.guard(nil, {userId: user.id}, {current_user: user})

expect(result).to eq(true)
end
Expand All @@ -54,7 +54,7 @@
user = User.new(id: '1', role: 'admin')

expect {
posts_field.guard(nil, {user_id: user.id}, {current_user: user})
posts_field.guard(nil, {userId: user.id}, {current_user: user})
}.to raise_error(GraphQL::Field::NoGuardError, "Guard lambda does not exist for Query.posts")
end

Expand All @@ -63,15 +63,15 @@
user = User.new(id: '1', role: 'admin')

expect {
posts_field.guard(nil, {user_id: user.id}, {current_user: user})
posts_field.guard(nil, {userId: user.id}, {current_user: user})
}.to raise_error(GraphQL::Field::NoGuardError, "Get your field by calling: Type.field_with_guard('posts')")
end

it 'returns false for a not authorized field' do
posts_field = PolicyObject::QueryType.field_with_guard('posts', PolicyObject::GraphqlPolicy)
user = User.new(id: '1', role: 'admin')

result = posts_field.guard(nil, {user_id: '2'}, {current_user: user})
result = posts_field.guard(nil, {userId: '2'}, {current_user: user})

expect(result).to eq(false)
end
Expand Down
4 changes: 4 additions & 0 deletions spec/spec_helper.rb
Expand Up @@ -2,7 +2,11 @@

require "bundler/setup"

ENV['GRAPHQL_RUBY_VERSION'] ||= '1_8'

if ENV['CI']
require 'simplecov'
SimpleCov.add_filter('spec')
require 'coveralls'
Coveralls.wear!
end
Expand Down

0 comments on commit c8341d4

Please sign in to comment.