graphql-permissions 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: b19b42395768459f48d770eeca3d951f5322f7340dbe1bdd2229ba209ddac71a
4
+ data.tar.gz: 00d83aeec4b6ac80570c260e4175ff1933d11e0ecef922e0ee2474e12f8acdc6
5
+ SHA512:
6
+ metadata.gz: e6ee32bb1a6624c5859a938c40cb19e2b529e91abb7df079d553fb972e64a94ac02f671934dfca232d4d2275ad7b0646b6c697fee96a4ae5dfc849107befdb1a
7
+ data.tar.gz: 9ee5d6ec4658bbf1b7ea5eb39308a4e9ad8bed8bf0e0bee03352a2a924e92f679bbbc9c1ea4a45ac60bf8e7f4d18233a6784a83a34ededf291887fbd8f299d91
@@ -0,0 +1,16 @@
1
+ name: Ruby
2
+
3
+ on: [push,pull_request]
4
+
5
+ jobs:
6
+ build:
7
+ runs-on: ubuntu-latest
8
+ steps:
9
+ - uses: actions/checkout@v2
10
+ - name: Set up Ruby
11
+ uses: ruby/setup-ruby@v1
12
+ with:
13
+ ruby-version: 3.0.1
14
+ bundler-cache: true
15
+ - name: Run the default task
16
+ run: bundle exec rake
data/.gitignore ADDED
@@ -0,0 +1,8 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
data/.rubocop.yml ADDED
@@ -0,0 +1,31 @@
1
+ require:
2
+ - rubocop-performance
3
+
4
+ AllCops:
5
+ NewCops: enable
6
+ SuggestExtensions: false
7
+ TargetRubyVersion: 2.7
8
+
9
+ Layout/LineLength:
10
+ Max: 120
11
+
12
+ Layout/AccessModifierIndentation:
13
+ EnforcedStyle: outdent
14
+
15
+ Layout/SpaceInLambdaLiteral:
16
+ EnforcedStyle: require_space
17
+
18
+ Lint/UnusedBlockArgument:
19
+ Exclude:
20
+ - lib/generators/graphql/permissions/templates/initializer.rb
21
+
22
+ Style/Documentation:
23
+ Enabled: false
24
+
25
+ Style/StringLiterals:
26
+ Enabled: true
27
+ EnforcedStyle: single_quotes
28
+
29
+ Style/StringLiteralsInInterpolation:
30
+ Enabled: true
31
+ EnforcedStyle: single_quotes
data/Gemfile ADDED
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ # Specify your gem's dependencies in graphql-permissions.gemspec
6
+ gemspec
7
+
8
+ gem 'rake', '~> 13.0'
9
+ gem 'rubocop', '~> 1.29'
10
+ gem 'rubocop-performance', '~> 1.13'
data/Gemfile.lock ADDED
@@ -0,0 +1,46 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ graphql-permissions (0.1.0)
5
+ graphql
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ ast (2.4.2)
11
+ graphql (2.0.7)
12
+ parallel (1.22.1)
13
+ parser (3.1.2.0)
14
+ ast (~> 2.4.1)
15
+ rainbow (3.1.1)
16
+ rake (13.0.6)
17
+ regexp_parser (2.4.0)
18
+ rexml (3.2.5)
19
+ rubocop (1.29.0)
20
+ parallel (~> 1.10)
21
+ parser (>= 3.1.0.0)
22
+ rainbow (>= 2.2.2, < 4.0)
23
+ regexp_parser (>= 1.8, < 3.0)
24
+ rexml (>= 3.2.5, < 4.0)
25
+ rubocop-ast (>= 1.17.0, < 2.0)
26
+ ruby-progressbar (~> 1.7)
27
+ unicode-display_width (>= 1.4.0, < 3.0)
28
+ rubocop-ast (1.17.0)
29
+ parser (>= 3.1.1.0)
30
+ rubocop-performance (1.13.3)
31
+ rubocop (>= 1.7.0, < 2.0)
32
+ rubocop-ast (>= 0.4.0)
33
+ ruby-progressbar (1.11.0)
34
+ unicode-display_width (2.1.0)
35
+
36
+ PLATFORMS
37
+ x86_64-linux
38
+
39
+ DEPENDENCIES
40
+ graphql-permissions!
41
+ rake (~> 13.0)
42
+ rubocop (~> 1.29)
43
+ rubocop-performance (~> 1.13)
44
+
45
+ BUNDLED WITH
46
+ 2.2.17
data/README.md ADDED
@@ -0,0 +1,138 @@
1
+ # GraphQL::Permissions
2
+
3
+ Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/graphql/permissions`. To experiment with that code, run `bin/console` for an interactive prompt.
4
+
5
+ TODO: Delete this and the text above, and describe your gem
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'graphql-permissions'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle install
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install graphql-permissions
22
+
23
+ Then run the Rails generator:
24
+
25
+ $ bin/rails generate graphql:permissions:install
26
+
27
+ This will create the base permissions object and interface types, as well as an initializer under `config/initializers/graphql_permissions.rb`
28
+
29
+ ## Usage
30
+
31
+ ```ruby
32
+ class PostType < Types::BaseObject
33
+ field :id, ID, null: false
34
+ field :body, String, null: false
35
+
36
+ permissions do
37
+ permission :update
38
+ permission :destroy
39
+ end
40
+ end
41
+ ```
42
+
43
+ The `Post` GraphQL object will expose a `permissions` property which returns a `PostPermissions` object.
44
+ Your GraphQL schema would look like:
45
+
46
+ ```graphql
47
+ type Post {
48
+ id: ID!
49
+ body: String!
50
+ permissions: PostPermissions!
51
+ }
52
+
53
+ type PostPermissions {
54
+ canUpdate: Boolean!
55
+ canDestroy: Boolean!
56
+ }
57
+ ```
58
+
59
+ ### Interface Permissions
60
+
61
+ GraphQL interfaces can also define permissions:
62
+
63
+ ```ruby
64
+ module LikeableType
65
+ include Types::BaseInterface
66
+
67
+ field :liked_by_you, Boolean, null: false
68
+
69
+ permissions do
70
+ permission :like
71
+ permission :dislike
72
+ end
73
+ end
74
+ ```
75
+
76
+ The `Likeable` GraphQL interface will expose a `permissions` property which returns a `LikeablePermissions` interface.
77
+
78
+ Permissions are automatically added to objects that implement an interface which defines permissions. For example:
79
+
80
+ ```ruby
81
+ class PostType < Types::BaseObject
82
+ implements LikeableType
83
+
84
+ # Permissions from `LikeableType` are automatically inherited
85
+ end
86
+ ```
87
+
88
+ Now the `Post` object implements the `Likeable` interface, and the `PostPermissions` object will automatically implement the `LikeablePermissions` interface.
89
+ The resulting GraphQL schema would look like:
90
+
91
+ ```graphql
92
+ interface Likeable {
93
+ likedByYou: Boolean!
94
+ permissions: LikeablePermissions!
95
+ }
96
+
97
+ interface LikeablePermissions {
98
+ canLike: Boolean!
99
+ canDislike: Boolean!
100
+ }
101
+
102
+ type Post implements Likeable {
103
+ id: ID!
104
+ body: String!
105
+ permissions: PostPermissions!
106
+ }
107
+
108
+ type PostPermissions implements LikeablePermissions {
109
+ canUpdate: Boolean!
110
+ canDestroy: Boolean!
111
+ }
112
+ ```
113
+
114
+ ### Custom Permission Checks
115
+
116
+ You can also provide a block when defining a permission to include custom permission or data-fetching logic:
117
+
118
+ ```ruby
119
+ class UserType < Types::BaseObject
120
+ # ...
121
+
122
+ permissions do
123
+ permission :ban do
124
+ context[:current_user].admin? && !object.admin?
125
+ end
126
+ end
127
+ end
128
+ ```
129
+
130
+ ## Development
131
+
132
+ After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
133
+
134
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
135
+
136
+ ## Contributing
137
+
138
+ Bug reports and pull requests are welcome on GitHub at https://github.com/mintyfresh/graphql-permissions.
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'rubocop/rake_task'
5
+
6
+ RuboCop::RakeTask.new
7
+
8
+ task default: :rubocop
data/bin/console ADDED
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'bundler/setup'
5
+ require 'graphql/permissions'
6
+
7
+ # You can add fixtures and/or initialization code here to make experimenting
8
+ # with your gem easier. You can also use a different console, if you like.
9
+
10
+ # (If you use this, don't forget to add pry to your Gemfile!)
11
+ # require "pry"
12
+ # Pry.start
13
+
14
+ require 'irb'
15
+ IRB.start(__FILE__)
data/bin/rubocop ADDED
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'rubocop' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ require 'pathname'
12
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile',
13
+ Pathname.new(__FILE__).realpath)
14
+
15
+ bundle_binstub = File.expand_path('bundle', __dir__)
16
+
17
+ if File.file?(bundle_binstub)
18
+ if /This file was generated by Bundler/.match?(File.read(bundle_binstub, 300))
19
+ load(bundle_binstub)
20
+ else
21
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
22
+ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
23
+ end
24
+ end
25
+
26
+ require 'rubygems'
27
+ require 'bundler/setup'
28
+
29
+ load Gem.bin_path('rubocop', 'rubocop')
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'lib/graphql/permissions/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'graphql-permissions'
7
+ spec.version = GraphQL::Permissions::VERSION
8
+ spec.authors = ['Minty Fresh']
9
+ spec.email = ['7896757+mintyfresh@users.noreply.github.com']
10
+
11
+ spec.summary = 'Permissions DSL for GraphQL Ruby'
12
+ spec.description = 'Expose user permissions in your GraphQL schema'
13
+ spec.homepage = 'https://github.com/mintyfresh/graphql-permissions'
14
+
15
+ spec.required_ruby_version = Gem::Requirement.new('>= 2.7.0')
16
+
17
+ spec.metadata['allowed_push_host'] = 'https://rubygems.org'
18
+ spec.metadata['rubygems_mfa_required'] = 'true'
19
+
20
+ spec.metadata['homepage_uri'] = spec.homepage
21
+ spec.metadata['source_code_uri'] = spec.homepage
22
+
23
+ # Specify which files should be added to the gem when it is released.
24
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
25
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
26
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{\A(?:test|spec|features)/}) }
27
+ end
28
+
29
+ spec.bindir = 'exe'
30
+ spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
31
+ spec.require_paths = ['lib']
32
+
33
+ spec.add_dependency 'graphql'
34
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Graphql
4
+ module Permissions
5
+ class InstallGenerator < ::Rails::Generators::Base
6
+ source_root File.expand_path('templates', __dir__)
7
+
8
+ def create_install
9
+ copy_file('initializer.rb', 'config/initializers/graphql_permissions.rb')
10
+ copy_file('base_permissions_object.rb', 'app/graphql/types/base_permissions_object.rb')
11
+ copy_file('base_permissions_interface.rb', 'app/graphql/types/base_permissions_interface.rb')
12
+
13
+ inject_into_file 'app/graphql/types/base_object.rb', after: "< GraphQL::Schema::Object\n" do
14
+ " extend GraphQL::Permissions::ObjectPermissions\n"
15
+ end
16
+
17
+ inject_into_file 'app/graphql/types/base_interface.rb', after: "include GraphQL::Schema::Interface\n" do
18
+ " extend GraphQL::Permissions::InterfacePermissions\n"
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Types
4
+ module BasePermissionsInterface
5
+ include Types::BaseInterface
6
+ extend GraphQL::Permissions::DSL
7
+ end
8
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Types
4
+ class BasePermissionsObject < Types::BaseObject
5
+ extend GraphQL::Permissions::DSL
6
+ end
7
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ GraphQL::Permissions.default_permission_handler = lambda do |action, object, context|
4
+ # TODO: Implement your own permission handler
5
+ #
6
+ # Example for Pundit:
7
+ # policy = Pundit.policy(context[:current_user], object)
8
+ # policy.send(:"#{action}?")
9
+ #
10
+ false
11
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GraphQL
4
+ module Permissions
5
+ module DSL
6
+ def included(klass)
7
+ super
8
+ klass.extend(GraphQL::Permissions::DSL)
9
+ end
10
+
11
+ # @param name [Symbol] The name of the permission.
12
+ # @return [void]
13
+ def permission(action, **options, &block)
14
+ field(:"can_#{action}", 'Boolean',
15
+ description: "Whether the current user can #{action} this object.",
16
+ **options, null: false, resolver_method: :"can_#{action}?")
17
+
18
+ define_method(:"can_#{action}?") do
19
+ block ? instance_exec(&block) : GraphQL::Permissions.default_permission_handler.call(action, object, context)
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GraphQL
4
+ module Permissions
5
+ module InterfacePermissions
6
+ # @return [Module, nil]
7
+ attr_reader :permissions_type
8
+
9
+ def included(klass)
10
+ super
11
+
12
+ klass.extend(GraphQL::Permissions::InterfacePermissions) unless klass.is_a?(Class)
13
+ return unless klass.is_a?(Class) && klass < GraphQL::Schema::Object && permissions_type
14
+
15
+ klass.permissions {} # rubocop:disable Lint/EmptyBlock
16
+ klass.permissions_type.implements(permissions_type)
17
+ end
18
+
19
+ # @return [Array<Module>]
20
+ def interfaces_with_permissions
21
+ own_interfaces.select { |interface| interface.respond_to?(:permissions_type) && interface.permissions_type }
22
+ end
23
+
24
+ def permissions(&block)
25
+ unless permissions_type
26
+ @permissions_type = create_permissions_type
27
+ const_set(:PermissionsType, @permissions_type)
28
+
29
+ implement_permissions_interfaces
30
+ define_permissions_field
31
+ end
32
+
33
+ permissions_type.class_eval(&block)
34
+ end
35
+
36
+ protected
37
+
38
+ # @return [Module]
39
+ def create_permissions_type
40
+ Module.new.tap do |type|
41
+ type.include(::Types::BasePermissionsInterface)
42
+ type.graphql_name("#{graphql_name}Permissions")
43
+ type.description("Permissions for this #{graphql_name}.")
44
+ end
45
+ end
46
+
47
+ # @return [void]
48
+ def implement_permissions_interfaces
49
+ # If this interface implements any other interfaces that defined their own permissions,
50
+ # Inherit those permissions in this interface's permissions type.
51
+ interfaces_with_permissions.each do |interface|
52
+ @permissions_type.implements(interface.permissions_type)
53
+ end
54
+
55
+ # If the interface defined any orphan types before its initial set of permissions,
56
+ # Update each of those types to implement the interface's permissions type.
57
+ orphan_types.each do |orphan_type|
58
+ orphan_type.permissions {} # Define an empty permission-set if not present.
59
+ orphan_type.permissions_type.implements(@permissions_type)
60
+ end
61
+ end
62
+
63
+ # @return [void]
64
+ def define_permissions_field
65
+ field(:permissions, @permissions_type, null: false, resolver_method: :object_for_permissions)
66
+ define_method(:object_for_permissions) { object || self }
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GraphQL
4
+ module Permissions
5
+ module ObjectPermissions
6
+ # @return [Class<GraphQL::Schema::Object>, nil]
7
+ attr_reader :permissions_type
8
+
9
+ # @return [Array<Module>]
10
+ def interfaces_with_permissions
11
+ interfaces.select { |interface| interface.respond_to?(:permissions_type) && interface.permissions_type }
12
+ end
13
+
14
+ def permissions(&block)
15
+ unless permissions_type
16
+ @permissions_type = create_permissions_type
17
+ const_set(:PermissionsType, @permissions_type)
18
+
19
+ implement_permissions_interfaces
20
+ define_permissions_field
21
+ end
22
+
23
+ permissions_type.class_eval(&block)
24
+ end
25
+
26
+ protected
27
+
28
+ # @return [Class]
29
+ def create_permissions_type
30
+ Class.new(superclass.permissions_type || ::Types::BasePermissionsObject).tap do |type|
31
+ type.graphql_name("#{graphql_name}Permissions")
32
+ type.description("Permissions for this #{graphql_name}.")
33
+ end
34
+ end
35
+
36
+ # @return [void]
37
+ def implement_permissions_interfaces
38
+ # If this object implements any interfaces that defined their own permissions,
39
+ # Inherit those permissions in this object's permissions type.
40
+ interfaces_with_permissions.each do |interface|
41
+ @permissions_type.implements(interface.permissions_type)
42
+ end
43
+ end
44
+
45
+ # @return [void]
46
+ def define_permissions_field
47
+ field(:permissions, @permissions_type, null: false, resolver_method: :object_for_permissions)
48
+ define_method(:object_for_permissions) { object || self }
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GraphQL
4
+ module Permissions
5
+ VERSION = '0.1.0'
6
+ end
7
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'graphql'
4
+ require_relative 'permissions/version'
5
+
6
+ module GraphQL
7
+ module Permissions
8
+ autoload :DSL, 'graphql/permissions/dsl'
9
+ autoload :InterfacePermissions, 'graphql/permissions/interface_permissions'
10
+ autoload :ObjectPermissions, 'graphql/permissions/object_permissions'
11
+
12
+ # @return [Proc]
13
+ def self.default_permission_handler
14
+ @default_permission_handler || raise('No default permission handler set')
15
+ end
16
+
17
+ # @param handler [Proc]
18
+ # @return [void]
19
+ def self.default_permission_handler=(handler)
20
+ @default_permission_handler = handler
21
+ end
22
+ end
23
+ end
metadata ADDED
@@ -0,0 +1,80 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: graphql-permissions
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Minty Fresh
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2022-05-10 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: graphql
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ description: Expose user permissions in your GraphQL schema
28
+ email:
29
+ - 7896757+mintyfresh@users.noreply.github.com
30
+ executables: []
31
+ extensions: []
32
+ extra_rdoc_files: []
33
+ files:
34
+ - ".github/workflows/main.yml"
35
+ - ".gitignore"
36
+ - ".rubocop.yml"
37
+ - Gemfile
38
+ - Gemfile.lock
39
+ - README.md
40
+ - Rakefile
41
+ - bin/console
42
+ - bin/rubocop
43
+ - bin/setup
44
+ - graphql-permissions.gemspec
45
+ - lib/generators/graphql/permissions/install_generator.rb
46
+ - lib/generators/graphql/permissions/templates/base_permissions_interface.rb
47
+ - lib/generators/graphql/permissions/templates/base_permissions_object.rb
48
+ - lib/generators/graphql/permissions/templates/initializer.rb
49
+ - lib/graphql/permissions.rb
50
+ - lib/graphql/permissions/dsl.rb
51
+ - lib/graphql/permissions/interface_permissions.rb
52
+ - lib/graphql/permissions/object_permissions.rb
53
+ - lib/graphql/permissions/version.rb
54
+ homepage: https://github.com/mintyfresh/graphql-permissions
55
+ licenses: []
56
+ metadata:
57
+ allowed_push_host: https://rubygems.org
58
+ rubygems_mfa_required: 'true'
59
+ homepage_uri: https://github.com/mintyfresh/graphql-permissions
60
+ source_code_uri: https://github.com/mintyfresh/graphql-permissions
61
+ post_install_message:
62
+ rdoc_options: []
63
+ require_paths:
64
+ - lib
65
+ required_ruby_version: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: 2.7.0
70
+ required_rubygems_version: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ requirements: []
76
+ rubygems_version: 3.2.15
77
+ signing_key:
78
+ specification_version: 4
79
+ summary: Permissions DSL for GraphQL Ruby
80
+ test_files: []