graphql-pundit-387 0.7.1

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 22581d5141ff37cf84000e97311a140bf3d800e8e269f7d46fb6142038e7b944
4
+ data.tar.gz: 437ffee93223873720aed7199e4822fac381c9e3ecb08e46028e9f42c9bb2142
5
+ SHA512:
6
+ metadata.gz: 1cdf6a962a9e1a353fbd61f518da86f72e0953586036343593e86a2ca2b609d7d3865fe11037aa65f422d252b7cc1124b23d8764b390a68e8a82080ddfec4c48
7
+ data.tar.gz: 7dc58ebb2a8e20470301ab0342a865a8189420974ebe805ffbd9feb78a2ad50c9cff098710be237719c2986e57abe248170ba2e0f5ecb148705031bbbe3b641e
@@ -0,0 +1,16 @@
1
+ ---
2
+ engines:
3
+ duplication:
4
+ enabled: true
5
+ config:
6
+ languages:
7
+ - ruby
8
+ fixme:
9
+ enabled: false
10
+ rubocop:
11
+ enabled: false
12
+ ratings:
13
+ paths:
14
+ - "**.rb"
15
+ exclude_paths:
16
+ - spec/
@@ -0,0 +1,13 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ /.vscode/
11
+
12
+ # rspec failure tracking
13
+ .rspec_status
@@ -0,0 +1,7 @@
1
+ ShowCopNames: true
2
+
3
+ fail_on_violations: false
4
+
5
+ ruby:
6
+ enabled: true
7
+ config_file: .rubocop.yml
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --color
2
+ --format Fuubar
3
+ --require spec_helper
@@ -0,0 +1,100 @@
1
+ AllCops:
2
+ TargetRubyVersion: 2.5
3
+ TargetRailsVersion: 5.1
4
+
5
+ CacheRootDirectory: /tmp
6
+ AllowSymlinksInCacheRootDirectory: true
7
+
8
+ Exclude:
9
+ - 'apidoc/**/*'
10
+ - 'bin/bundle'
11
+ - 'bin/rails'
12
+ - 'bin/rake'
13
+ - 'bin/setup'
14
+ - 'bin/spring'
15
+ - 'bin/update'
16
+ - 'config/deploy/*.rb'
17
+ - 'config/mixins/applications/*.rb'
18
+ - 'data/**/*'
19
+ - 'db/schema.rb'
20
+ - 'node_modules/**/*'
21
+ - 'spec/dummy/**/*'
22
+ - 'vendor/**/*'
23
+ - 'repositories/**/*'
24
+ - 'repos/**/*'
25
+ - 'tmp/**/*'
26
+
27
+ Layout/AlignParameters:
28
+ Enabled: false
29
+
30
+ Layout/DotPosition:
31
+ EnforcedStyle: trailing
32
+
33
+ Layout/MultilineMethodCallIndentation:
34
+ EnforcedStyle: indented
35
+
36
+ Layout/SpaceInsideHashLiteralBraces:
37
+ EnforcedStyle: no_space
38
+
39
+ Metrics/BlockLength:
40
+ Exclude:
41
+ - 'app/graphql/**/*'
42
+ - 'config/routes.rb'
43
+ - 'config/environments/**/*'
44
+ - 'config/initializers/devise.rb'
45
+ - 'lib/tasks/**/*.rake'
46
+ - 'spec/**/*'
47
+ - 'db/migrate/*'
48
+ - '*.gemspec'
49
+
50
+ Metrics/LineLength:
51
+ Exclude:
52
+ - 'app/graphql/**/*_enum.rb'
53
+ - 'config/initializers/devise.rb'
54
+
55
+ Naming/FileName:
56
+ Exclude:
57
+ - config/deploy/*.rb
58
+ - config/mixins/applications/*.rb
59
+ - lib/git-shell.rb
60
+ - lib/graphql-pundit.rb
61
+ - lib/hets-agent.rb
62
+ - lib/ontohub-models.rb
63
+ - spec/lib/git-shell_spec.rb
64
+
65
+ Naming/UncommunicativeMethodParamName:
66
+ Exclude:
67
+ - 'spec/**/*'
68
+
69
+ Style/Documentation:
70
+ Exclude:
71
+ - 'app/indexers/**/*'
72
+ - 'spec/**/*'
73
+
74
+ Style/DoubleNegation:
75
+ Enabled: false
76
+
77
+ Style/FormatStringToken:
78
+ Enabled: false
79
+
80
+ Style/NumericLiterals:
81
+ Enabled: false
82
+
83
+ Style/PercentLiteralDelimiters:
84
+ PreferredDelimiters:
85
+ default: ()
86
+ '%i': '()'
87
+ '%I': '()'
88
+ '%r': '{}'
89
+ '%w': '()'
90
+ '%W': '()'
91
+
92
+ Style/SymbolArray:
93
+ Exclude:
94
+ - 'db/migrate/**'
95
+
96
+ Style/TrailingCommaInArrayLiteral:
97
+ EnforcedStyleForMultiline: comma
98
+
99
+ Style/TrailingCommaInHashLiteral:
100
+ EnforcedStyleForMultiline: comma
@@ -0,0 +1 @@
1
+ 2.5.1
@@ -0,0 +1,7 @@
1
+ linters:
2
+ rubocop:
3
+ fixer: true
4
+ shellcheck:
5
+ shell: bash
6
+ fixers:
7
+ enable: true
@@ -0,0 +1,21 @@
1
+ sudo: false
2
+ dist: trusty
3
+
4
+ language: ruby
5
+
6
+ rvm:
7
+ - 2.2.9
8
+ - 2.3.6
9
+ - 2.4.3
10
+ - 2.5.1
11
+
12
+ notifications:
13
+ email: false
14
+
15
+ matrix:
16
+ fast_finish: true
17
+ allow_failures:
18
+ - rvm: 2.2.9
19
+
20
+ script:
21
+ - bundle exec rspec --format progress
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ # Specify your gem's dependencies in graphql-pundit.gemspec
6
+ gemspec
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2017 Tom Gehrke
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,372 @@
1
+ This fork was created because of a bug when authorization in mutations fail. With this error:
2
+ ArgumentError (wrong number of arguments (given 2, expected 4)):
3
+ when using "prepend GraphQL::Pundit::Scope" in Baseobject
4
+
5
+ Fork does not fix the error but just disables scopes as its not something thats being used in my app.
6
+
7
+ --
8
+
9
+ [![Gem](https://img.shields.io/gem/v/graphql-pundit.svg)](https://rubygems.org/gems/graphql-pundit)
10
+ [![Build Status](https://travis-ci.org/ontohub/graphql-pundit.svg?branch=master)](https://travis-ci.org/ontohub/graphql-pundit)
11
+ [![Coverage Status](https://codecov.io/gh/ontohub/graphql-pundit/branch/master/graph/badge.svg)](https://codecov.io/gh/ontohub/graphql-pundit)
12
+ [![Code Climate](https://codeclimate.com/github/ontohub/graphql-pundit/badges/gpa.svg)](https://codeclimate.com/github/ontohub/graphql-pundit)
13
+ [![GitHub issues](https://img.shields.io/github/issues/ontohub/graphql-pundit.svg?maxAge=2592000)](https://waffle.io/ontohub/ontohub-backend?source=ontohub%2Fgraphql-pundit)
14
+
15
+ # GraphQL::Pundit
16
+
17
+ ## Installation
18
+
19
+ Add this line to your application's Gemfile:
20
+
21
+ ```ruby
22
+ gem 'graphql-pundit', '~> 0.7.0'
23
+ ```
24
+
25
+ And then execute:
26
+
27
+ ```bash
28
+ $ bundle
29
+ ```
30
+
31
+ ### Upgrade Notice
32
+
33
+ If you're upgrading from an earlier version, make sure to delete your
34
+ `bootsnap` cache, to avoid a load error (see
35
+ [this issue](https://github.com/ontohub/graphql-pundit/issues/51)).
36
+ The cache files are usually located in the `tmp` directory in your
37
+ repository and are named `bootsnap-compile-cache` and
38
+ `bootsnap-load-path-cache`.
39
+
40
+ ## Usage
41
+
42
+ ### Class based API (`graphql-ruby >= 1.8`)
43
+
44
+ To use `graphql-pundit` with the class based API introduced in `graphql`
45
+ version 1.8, the used `Field` class must be changed:
46
+
47
+ It is recommended to have application-specific base classes, from which the
48
+ other types inherit (similar to having an `ApplicationController` from which
49
+ all other controllers inherit). That base class can be used to define a
50
+ custom field class, on which the new `graphql-pundit` API builds.
51
+
52
+ ```ruby
53
+ class BaseObject < GraphQL::Schema::Object
54
+ field_class GraphQL::Pundit::Field
55
+ end
56
+ ```
57
+
58
+ All other object types now inherit from `BaseObject`, and that is all that is
59
+ needed to get `graphql-pundit` working with the class based API.
60
+
61
+ In case you already use a custom field type, or if you want to use a context
62
+ key other than `:current_user` to make your current user available, you can
63
+ include `graphql-pundit`'s functionality into your field type:
64
+
65
+ ```ruby
66
+ class MyFieldType < GraphQL::Schema::Field
67
+ prepend GraphQL::Pundit::Scope
68
+ prepend GraphQL::Pundit::Authorization
69
+
70
+ current_user :me # if the current_user is passed in as context[:me]
71
+ end
72
+ ```
73
+
74
+ When using this, make sure the order of `prepend`s is correct, as you usually want the authorization to happen **first**, which means that it needs to be `prepend`ed **after** the scopes (if you need them).
75
+
76
+ #### Usage
77
+
78
+ ```ruby
79
+ class Car < BaseObject
80
+ field :trunk, CarContent, null: true,
81
+ authorize: true
82
+ end
83
+ ```
84
+
85
+ The above example shows the most basic usage of this gem. The example would
86
+ use `CarPolicy#trunk?` for authorizing access to the field, passing in the
87
+ parent object (in this case probably a `Car` model).
88
+
89
+ ##### Options
90
+
91
+ Two styles of declaring fields is supported:
92
+
93
+ 1. the inline style, passing all the options as a hash to the field method
94
+ 2. the block style
95
+
96
+ Both styles are presented below side by side.
97
+
98
+ ###### `authorize` and `authorize!`
99
+
100
+ To use authorization on a field, you **must** pass either the `authorize` or
101
+ `authorize!` option. Both options will cause the field to return `nil` if the
102
+ access is unauthorized, but `authorize!` will also add an error message (e.g.
103
+ for usage with mutations).
104
+
105
+ `authorize` and `authorize!` can be passed three different things:
106
+
107
+ ```ruby
108
+ class User < BaseObject
109
+ # will use the `UserPolicy#display_name?` method
110
+ field :display_name, ..., authorize: true
111
+ field :display_name, ... do
112
+ authorize
113
+ end
114
+
115
+ # will use the passed lambda instead of a policy method
116
+ field :password_hash, ..., authorize: ->(obj, args, ctx) { ... }
117
+ field :password_hash, ... do
118
+ authorize ->(obj, args, ctx) { ... }
119
+ end
120
+
121
+ # will use the `UserPolicy#personal_info?` method
122
+ field :email, ..., authorize: :personal_info
123
+ field :email, ... do
124
+ authorize :personal_info
125
+ end
126
+ end
127
+ ```
128
+
129
+ * `true` will trigger the inference mechanism, meaning that the method that will be called on the policy class will be inferred from the (snake_case) field name.
130
+ * a lambda function that will be called with the parent object, the arguments of the field and the context object; if the lambda returns a truthy value, authorization succeeds; otherwise (including thrown exceptions), authorization fails
131
+ * a string or a symbol that corresponds to the policy method that should be called **minus the "?"**
132
+
133
+ ###### `policy`
134
+
135
+ `policy` is an optional argument that can also be passed three different values:
136
+
137
+ ```ruby
138
+ class User < BaseObject
139
+ # will use the `UserPolicy#display_name?` method (default inference)
140
+ field :display_name, ..., authorize: true, policy: nil
141
+ field :display_name do
142
+ authorize policy: nil
143
+ end
144
+
145
+ # will use OtherUserPolicy#password_hash?
146
+ field :password_hash, ...,
147
+ authorize: true,
148
+ policy: ->(obj, args, ctx) { OtherUserPolicy }
149
+ field :password_hash, ... do
150
+ authorize policy: ->(obj, args, ctx) { OtherUserPolicy }
151
+ end
152
+
153
+ # will use MemberPolicy#email?
154
+ field :email, ..., authorize: true, policy: MemberPolicy
155
+ field :email, ... do
156
+ authorize policy: MemberPolicy
157
+ end
158
+ end
159
+ ```
160
+
161
+ * `nil` is the default behavior and results in inferring the policy class from the record (see below)
162
+ * a lambda function that will be called with the parent object, the arguments of the field and the context object; the return value of this function will be used as the policy class
163
+ * an actual policy class
164
+
165
+ ###### `record`
166
+
167
+ `record` can be used to pass a different value to the policy. Like `policy`,
168
+ this argument also can receive three different values:
169
+
170
+ ```ruby
171
+ class User < BaseObject
172
+ # will use the parent object
173
+ field :display_name, ..., authorize: true, record: nil
174
+ field :display_name do
175
+ authorize record: nil
176
+ end
177
+
178
+ # will use the current user as the record
179
+ field :password_hash, ...,
180
+ authorize: true,
181
+ record: ->(obj, args, ctx) { ctx[:current_user] }
182
+ field :password_hash, ... do
183
+ authorize record: ->(obj, args, ctx) { ctx[:current_user] }
184
+ end
185
+
186
+ # will use AccountPolicy#email? with the first account as the record (the policy was inferred from the record class)
187
+ field :email, ..., authorize: true, record: Account.first
188
+ field :email, ... do
189
+ authorize record: Account.first
190
+ end
191
+ end
192
+ ```
193
+
194
+ * `nil` is again used for the inference; in this case, the parent object is used
195
+ * a lambda function, again called with the parent object, the field arguments and the context object; the result will be used as the record
196
+ * any other value that will be used as the record
197
+
198
+ Using `record` can be helpful for e.g. mutations, where you need a value to
199
+ initialize the policy with, but for mutations there is no parent object.
200
+
201
+ ###### `before_scope` and `after_scope`
202
+
203
+ `before_scope` and `after_scope` can be used to apply Pundit scopes to the
204
+ fields. Both options can be combined freely within one field. The result of
205
+ `before_scope` is passed to the resolver as the "parent object", while the
206
+ result of `after_scope` is returned as the result of the field.
207
+
208
+ ```ruby
209
+ class User < BaseObject
210
+ # will use the `PostPolicy::Scope` before the resolver
211
+ field :posts, ..., before_scope: true
212
+ field :posts, ... do
213
+ before_scope
214
+ end
215
+
216
+ # will use the passed lambda after the resolver
217
+ field :comments, ..., after_scope: ->(comments, args, ctx) { ... }
218
+ field :comments, ... do
219
+ after_scope ->(comments, args, ctx) { ... }
220
+ end
221
+
222
+ # will use the `FriendPolicy::Scope`
223
+ field :friends, ..., after_scope: FriendPolicy
224
+ field :friends, ... do
225
+ after_scope FriendPolicy
226
+ end
227
+ end
228
+ ```
229
+
230
+ * `true` will trigger the inference mechanism, where the policy class, which contains the scope class, is inferred based on either the parent object (for `before_scope`) or the result of the resolver (for `after_scope`).
231
+ * a lambda function, that will be called with the parent object (for `before_scope`) or the result of the resolver (for `after_scope`), the field arguments and the context
232
+ * a policy class that contains a `Scope` class (this does not actually have to be a policy class, but could also be a module containing a `Scope` class)
233
+
234
+ ###### Combining options
235
+
236
+ All options can be combined with one another (except `authorize` and `authorize!`; please don't do that). Examples:
237
+
238
+ ```ruby
239
+ # MemberPolicy#name? initialized with the parent
240
+ field :display_name, ..., authorize: :name,
241
+ policy: MemberPolicy
242
+
243
+ # UserPolicy#display_name? initialized with user.account_data
244
+ field :display_name, ..., do
245
+ authorize policy: UserPolicy,
246
+ record: ->(obj, args, ctx) { obj.account_data }
247
+ end
248
+ ```
249
+
250
+ ### Legacy `define` API
251
+
252
+ The legacy `define` based API will be supported until it is removed from the
253
+ `graphql` gem (as planned for version 1.10).
254
+
255
+ #### Add the authorization middleware
256
+
257
+ Add the following to your GraphQL schema:
258
+
259
+ ```ruby
260
+ MySchema = GraphQL::Schema.define do
261
+ ...
262
+ instrument(:field, GraphQL::Pundit::Instrumenter.new)
263
+ ...
264
+ end
265
+ ```
266
+
267
+ By default, `ctx[:current_user]` will be used as the user to authorize. To change that behavior, pass a symbol to `GraphQL::Pundit::Instrumenter`.
268
+
269
+ ```ruby
270
+ GraphQL::Pundit::Instrumenter.new(:me) # will use ctx[:me]
271
+ ```
272
+
273
+ #### Authorize fields
274
+
275
+ For each field you want to authorize via Pundit, add the following code to the field definition:
276
+
277
+ ```ruby
278
+ field :email do
279
+ authorize # will use UserPolicy#email?
280
+ resolve ...
281
+ end
282
+ ```
283
+
284
+ By default, this will use the Policy for the parent object (the first argument passed to the resolve proc), checking for `:email?` for the current user. Sometimes, the field name will differ from the policy method name, in which case you can specify it explicitly:
285
+
286
+ ```ruby
287
+ field :email do
288
+ authorize :read_email # will use UserPolicy#read_email?
289
+ resolve ...
290
+ end
291
+ ```
292
+
293
+ Now, in some cases you'll want to use a different policy, or in case of mutations, the passed object might be `nil`:
294
+
295
+ ```ruby
296
+ field :createUser
297
+ authorize! :create, policy: User # or User.new; will use UserPolicy#create?
298
+ resolve ...
299
+ end
300
+ ```
301
+
302
+ This will use the `:create?` method of the `UserPolicy`. You can also pass in objects instead of a class (or symbol), if you wish to authorize the user for the specific object.
303
+
304
+ If you want to pass a different value to the policy, you can use the keyword argument `record`:
305
+
306
+ ```ruby
307
+ field :createUser
308
+ authorize! :create, record: User.new # or User.new; will use UserPolicy#create?
309
+ resolve ...
310
+ end
311
+ ```
312
+
313
+ You can also pass a `lambda` as a record. This receives the usual three arguments (parent value, arguments, context) and returns the value to be used as a record.
314
+
315
+ You might have also noticed the use of `authorize!` instead of `authorize` in this example. The difference between the two is this:
316
+
317
+ * `authorize` will set the field to `nil` if authorization fails
318
+ * `authorize!` will set the field to `nil` and add an error to the response if authorization fails
319
+
320
+ You would normally want to use `authorize` for fields in queries, that only e.g. the owner of something can see, while `authorize!` would be usually used in mutations, where you want to communicate to the client that the operation failed because the user is unauthorized.
321
+
322
+ If you still need more control over how policies are called, you can pass a lambda to `authorize`:
323
+
324
+ ```ruby
325
+ field :email
326
+ authorize ->(obj, args, ctx) { UserPolicy.new(obj, ctx[:me]).private_data?(:email) }
327
+ resolve ...
328
+ end
329
+ ```
330
+
331
+ If the lambda returns a falsy value or raises a `Pundit::UnauthorizedError` the field will resolve to `nil`, if it returns a truthy value, control will be passed to the resolve function. Of course, this can be used with `authorize!` as well.
332
+
333
+ #### Scopes
334
+
335
+ Pundit scopes are supported by using `before_scope` and `after_scope` in the field definition
336
+
337
+ ```ruby
338
+ field :posts
339
+ after_scope
340
+ resolve ...
341
+ end
342
+ ```
343
+
344
+ Passing no arguments to `after_scope` and `before_scope` will infer the policy to use from the value it is passed: `before_scope` is run before `resolve` and will receive the parent object, `after_scope` will be run after `resolve` and receives the output of `resolve`. You can also pass a proc or a policy class to both `_scope`s:
345
+
346
+ ```ruby
347
+ field :posts
348
+ before_scope ->(_root, _args, ctx) { Post.where(owner: ctx[:current_user]) }
349
+ resolve ->(posts, args, ctx) { ... }
350
+ end
351
+ ```
352
+
353
+ ```ruby
354
+ field :posts
355
+ after_scope PostablePolicy
356
+ resolve ...
357
+ end
358
+ ```
359
+
360
+ ## Development
361
+
362
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
363
+
364
+ 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 tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
365
+
366
+ ## Contributing
367
+
368
+ Bug reports and pull requests are welcome on GitHub at https://github.com/ontohub/graphql-pundit.
369
+
370
+ ## License
371
+
372
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).