ezcater_rubocop 6.0.3 → 6.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 144220e45db4ba03e7754c0f656cafe7650da1669157b65396c818762e7d9185
4
- data.tar.gz: b1e19818de9418e2a822ef0d1a3c067870ed36d26c7addb6d831776b4590a25d
3
+ metadata.gz: ae4de56eb716caa74ed16c478e3b727fe7a6d4b8bd5d2cdf3ff69900a270b22b
4
+ data.tar.gz: acc031ba45d8fd09ec70dd131ad8e6948d31cd187b39819ce5923c8462fde004
5
5
  SHA512:
6
- metadata.gz: 6da4228e123e62619f9ac2e66f53e766cd8a15160f6362fc7e33009b39749028a6e1dd4d835caa8fa101afe71dc743f6947622e43d2d3530b1ee23b3e539fadc
7
- data.tar.gz: 6cbe86a738c2567d5829b58b18cc23e13f05125b4c19ebd7ad41ddbcc5945cc08774740353708488e9c88235bdf85dc5f317f7654322255c8e9bcc10c4489076
6
+ metadata.gz: 4031f298709b7870fac309511a37a0e00ec5da5fa722188aac31550137b6d313335f7f8b8f569b0b4e80251a8b1ac0efc9870585f982e098f5277875552229e8
7
+ data.tar.gz: c2cf80f65849d0a01dc2a0ccb8ff8bea65ecaecff167aefa6c4102adc5d956d6ca557583575905169b5c10004bf2c72455e22e73be27660c0b4bdb180118926c
data/CHANGELOG.md CHANGED
@@ -6,6 +6,11 @@ This gem is moving onto its own [Semantic Versioning](https://semver.org/) schem
6
6
 
7
7
  Prior to v1.0.0 this gem was versioned based on the `MAJOR`.`MINOR` version of RuboCop. The first release of the ezcater_rubocop gem was `v0.49.0`.
8
8
 
9
+ ## 6.1.0
10
+
11
+ - Add `Ezcater/GraphQL/NotAuthorizedScalarField` Cop which enforces the use
12
+ of authorization for scalar GraphQL fields. Not enforced by default.
13
+
9
14
  ## 6.0.3
10
15
  - Fix `FeatureFlagActive` cop so that it allows feature flag names to be constants and dot method calls in addition to strings.
11
16
 
data/README.md CHANGED
@@ -81,6 +81,9 @@ not add cops with `enabled: false` unless you want that cop to always be disable
81
81
 
82
82
  * [FeatureFlagActive](https://github.com/ezcater/ezcater_rubocop/blob/main/lib/rubocop/cop/ezcater/feature_flag_active.rb) - Enforce the proper arguments are given to `EzcaterFeatureFlag.active?`
83
83
  * [FeatureFlagNameValid](https://github.com/ezcater/ezcater_rubocop/blob/main/lib/rubocop/cop/ezcater/feature_flag_name_valid.rb) - Enforce correct flag name format is being used.
84
+ * [GraphQL/NotAuthorizedScalarField] - Enforces the use of
85
+ authorization (pundit or, optionally, the guard pattern) for scalar
86
+ fields. See examples within class comment for additional configuration.
84
87
  * [RailsConfiguration](https://github.com/ezcater/ezcater_rubocop/blob/main/lib/rubocop/cop/ezcater/rails_configuration.rb) - Enforce use of `Rails.configuration` instead of `Rails.application.config`.
85
88
  * [RequireGqlErrorHelpers](https://github.com/ezcater/ezcater_rubocop/blob/main/lib/rubocop/cop/ezcater/require_gql_error_helpers.rb) - Use the helpers provided by `GQLErrors` instead of raising `GraphQL::ExecutionError` directly.
86
89
  * [RspecDotNotSelfDot](https://github.com/ezcater/ezcater_rubocop/blob/main/lib/rubocop/cop/ezcater/rspec_dot_not_self_dot.rb) - Enforce ".<class method>" instead of "self.<class method>" and "::<class method>" for example group description.
@@ -90,6 +93,8 @@ not add cops with `enabled: false` unless you want that cop to always be disable
90
93
  * [RspecRequireHttpStatusMatcher](https://github.com/ezcater/ezcater_rubocop/blob/main/lib/rubocop/cop/ezcater/rspec_require_http_status_matcher.rb) - Use the HTTP status code matcher, like `expect(response).to have_http_status :bad_request`, rather than `expect(response.code).to eq 400`
91
94
  * [StyleDig](https://github.com/ezcater/ezcater_rubocop/blob/main/lib/rubocop/cop/ezcater/style_dig.rb) - Recommend `dig` for deeply nested access.
92
95
 
96
+ [GraphQL/NotAuthorizedScalarField]: https://github.com/ezcater/ezcater_rubocop/blob/main/lib/rubocop/cop/ezcater/graphql/not_authorized_scalar_field.rb)
97
+
93
98
  ## Development
94
99
 
95
100
  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.
@@ -104,6 +109,47 @@ To release a new version, update the version number in `version.rb`, merge your
104
109
 
105
110
  Bug reports and pull requests are welcome on GitHub at https://github.com/ezcater/ezcater_rubocop.
106
111
 
112
+ ### Adding New Cops
113
+
114
+ New cops can be generated via the `new_cop` rake task which generates
115
+ the cop, the spec, updates imports, and adds configuration. Example:
116
+
117
+ ``` shell
118
+ rake 'new_cop[Ezcater/foo_bar]'
119
+ ```
120
+
121
+ Follow the instructions after the task executes and update code as
122
+ necessary for consistency.
123
+
124
+
125
+ In addition, you need to:
126
+
127
+ 1. Add the cop to the "Custom Cops" section of this README
128
+ 2. Bump the version.
129
+ 3. Add a CHANGELOG entry.
130
+
131
+
132
+ ### Version Bumps & Changelog Entries
133
+
134
+ The version for this gem follows [Semantic Versioning]:
135
+
136
+ 1. Bump the MAJOR version for breaking changes. Example: new cop,
137
+ enabled by default and which cannot be safely autofixed.
138
+
139
+ 2. Bump the MINOR version for new functionality which will not disrupt
140
+ projects which depend on this gem. Example: new cop, not enabled by
141
+ default or which can safely be autofixed.
142
+
143
+ 3. Bump the PATCH version for backwards compatible bugfixes.
144
+
145
+ [Semantic Versioning]: https://semver.org/
146
+
147
+ The version does not need to be bumped and the changelog does not need
148
+ to be updated for chores which do not affect users of this
149
+ gem. Example: updating CI. Omitting these details helps keep the
150
+ signal-to-noise ratio high for people upgrading the gem as these types
151
+ of changes will not affect them.
152
+
107
153
  ## License
108
154
 
109
155
  The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
data/config/default.yml CHANGED
@@ -18,6 +18,14 @@ Ezcater/FeatureFlagNameValid:
18
18
  Description: "Enforce correct flag name format is being used."
19
19
  Enabled: true
20
20
 
21
+ Ezcater/GraphQL/NotAuthorizedScalarField:
22
+ Description: 'Enforce the use of authorization for scalar GraphQL fields.'
23
+ Include:
24
+ - 'app/graphql/**/*.rb'
25
+ - 'packs/**/graphql/**/*.rb'
26
+ Enabled: false
27
+ VersionAdded: '6.1.0'
28
+
21
29
  Ezcater/RspecDotNotSelfDot:
22
30
  Description: 'Enforce ".<class method>" instead of "self.<class method>" for example group description.'
23
31
  Enabled: true
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module EzcaterRubocop
4
- VERSION = "6.0.3"
4
+ VERSION = "6.1.0"
5
5
  end
@@ -19,6 +19,7 @@ RuboCop::ConfigLoader.instance_variable_set(:@default_configuration, config)
19
19
  require "rubocop/cop/ezcater/direct_env_check"
20
20
  require "rubocop/cop/ezcater/feature_flag_active"
21
21
  require "rubocop/cop/ezcater/feature_flag_name_valid"
22
+ require "rubocop/cop/ezcater/graphql/not_authorized_scalar_field"
22
23
  require "rubocop/cop/ezcater/rails_configuration"
23
24
  require "rubocop/cop/ezcater/rails_env"
24
25
  require "rubocop/cop/ezcater/ruby_timeout"
@@ -0,0 +1,198 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Ezcater
6
+ module GraphQL
7
+ # Enforces authorization for scalar GraphQL fields. It
8
+ # identifies scalar fields by matching against the standard
9
+ # [graphql-ruby scalar types] by default.
10
+ #
11
+ # [graphql-ruby scalar types]: https://graphql-ruby.org/type_definitions/scalars.html
12
+ #
13
+ # @safety
14
+ # This cop is unable to autocorrect violations as decision making is
15
+ # required on the part of the developer.
16
+ #
17
+ # @example AllowGuards: false (default)
18
+ # # Requires that pundit authorization is used on scalar fields.
19
+ # # @see https://graphql-ruby.org/authorization/pundit_integration.html#authorizing-fields
20
+ #
21
+ # # bad
22
+ # field :secret_name, String
23
+ #
24
+ # # bad
25
+ # field :secret_name, String
26
+ #
27
+ # def secret_name
28
+ # SecretNameGuard.new(context, object).guard do |person|
29
+ # person.secret_name
30
+ # end
31
+ # end
32
+
33
+ # # good
34
+ # field :name, String, pundit_role: :owner
35
+ #
36
+ # # good
37
+ # field :name, String, pundit_role: :view, pundit_policy_class: "SecretNamePolicy"
38
+ #
39
+ # @example AllowGuards: true
40
+ # # In addition to the pundit enforcement demonstrated in the previous
41
+ # # example, guard-style authentication is allowed for scalar fields
42
+ # # when a resolver is defined in the same class.
43
+ #
44
+ # # bad
45
+ # field :secret_name, String
46
+ #
47
+ # def secret_name
48
+ # "Rumplestiltskin"
49
+ # end
50
+ #
51
+ # # good
52
+ # field :secret_name, String
53
+ #
54
+ # def secret_name
55
+ # SecretNameGuard.new(context, object).guard do |person|
56
+ # person.secret_name
57
+ # end
58
+ # end
59
+ #
60
+ # @example AdditionalScalarTypes: [] (default)
61
+ # # This option specifies additional scalar types for this cop to pay
62
+ # # attention to. By default, this list is empty.
63
+ #
64
+ # # bad
65
+ # field :secret_id, ID
66
+ #
67
+ # # good (i.e. the cop doesn't pay attention to UUID by default)
68
+ # field :secret_id, UUID
69
+ #
70
+ # @example AdditionalScalarTypes: ["UUID"]
71
+ # # This example adds UUID to the types to observe.
72
+ #
73
+ # # bad
74
+ # field :secret_id, UUID
75
+ #
76
+ # # good
77
+ # field :secret_id, pundit_role: owner
78
+ #
79
+ # @example IgnoredFieldNames: [] (default)
80
+ # # This option specifies field names to ignore.
81
+ #
82
+ # # bad (the field name is not in the ignore list)
83
+ # field :id, ID
84
+ #
85
+ # @example IgnoredFieldNames: ["id"]
86
+ # # This examples adds "id" to the list of ignored field names.
87
+ #
88
+ # # good
89
+ # field :id, ID
90
+ #
91
+ class NotAuthorizedScalarField < Base
92
+ include RuboCop::GraphQL::NodePattern
93
+
94
+ MSG = "Ezcater/GraphQL/NotAuthorizedScalarFields: must be authorized."
95
+
96
+ # https://graphql-ruby.org/type_definitions/scalars.html
97
+ STANDARD_SCALAR_TYPES = %w(BigInt Boolean Float Int ID ISO8601Date ISO8601DateTime ISO8601Duration JSON
98
+ String).freeze
99
+
100
+ # @!method field_type(node)
101
+ def_node_matcher :field_type, <<~PATTERN
102
+ (send nil? :field _ (:const nil? $_) ...)
103
+ PATTERN
104
+
105
+ # @!method field_with_body_type(node)
106
+ def_node_matcher :field_with_body_type, <<~PATTERN
107
+ (block (send nil? :field _ (:const nil? $_) ...) ...)
108
+ PATTERN
109
+
110
+ # @!method field_with_guard_in_body?(node)
111
+ def_node_matcher :field_with_guard_in_body?, <<~PATTERN
112
+ (block
113
+ (send nil? :field ...)
114
+ _?
115
+ (block
116
+ (send
117
+ (send
118
+ (:const ...) :new
119
+ (send nil? :context)
120
+ (send nil? :object)) :guard)
121
+ ...) ...)
122
+ PATTERN
123
+
124
+ # @!method field_with_pundit?(node)
125
+ def_node_matcher :field_with_pundit?, <<~PATTERN
126
+ (send nil? :field _ _ (hash <(pair (sym :pundit_role) _) ...>))
127
+ PATTERN
128
+
129
+ # @!method field_with_pundit_with_body?(node)
130
+ def_node_matcher :field_with_pundit_with_body?, <<~PATTERN
131
+ (block (send nil? :field _ _ (hash <(pair (sym :pundit_role) _) ...>)) ...)
132
+ PATTERN
133
+
134
+ # @!method contains_resolver_method_with_guard?(node)
135
+ def_node_search :contains_resolver_method_with_guard?, <<~PATTERN
136
+ (def %1
137
+ (args)
138
+ (block
139
+ (send
140
+ (send
141
+ (:const ...) :new
142
+ (send nil? :context)
143
+ (send nil? :object)) :guard)
144
+ ...) ...)
145
+ PATTERN
146
+
147
+ def on_class(node)
148
+ body = RuboCop::GraphQL::SchemaMember.new(node).body
149
+
150
+ each_field_node(body) do |field_node|
151
+ check_field_for_offense(field_node, node)
152
+ end
153
+ end
154
+
155
+ private
156
+
157
+ def allow_guards?
158
+ @_allow_guards ||= !!cop_config["AllowGuards"]
159
+ end
160
+
161
+ def check_field_for_offense(field, class_node)
162
+ return if field_with_pundit?(field.node) || field_with_pundit_with_body?(field.node)
163
+ return if ignored_field_names.include?(field.underscore_name)
164
+
165
+ type = field_type(field.node) || field_with_body_type(field.node)
166
+ return unless scalar_types.include?(type.to_s)
167
+
168
+ return if allow_guards? && (
169
+ field_with_guard_in_body?(field.node) ||
170
+ contains_resolver_method_with_guard?(class_node, field.underscore_name.to_sym)
171
+ )
172
+
173
+ add_offense(field.node)
174
+ end
175
+
176
+ def each_field_node(body)
177
+ return unless body
178
+
179
+ body.each do |node|
180
+ yield RuboCop::GraphQL::Field.new(node) if field?(node)
181
+ end
182
+ end
183
+
184
+ def ignored_field_names
185
+ @_ignored_field_names ||= (cop_config["IgnoredFieldNames"] || []).to_set
186
+ end
187
+
188
+ def scalar_types
189
+ return @_scalar_types if defined?(@_scalar_types)
190
+
191
+ additional_scalar_types = cop_config["AdditionalScalarTypes"] || []
192
+ @_scalar_types = STANDARD_SCALAR_TYPES.to_set.merge(additional_scalar_types)
193
+ end
194
+ end
195
+ end
196
+ end
197
+ end
198
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ezcater_rubocop
3
3
  version: !ruby/object:Gem::Version
4
- version: 6.0.3
4
+ version: 6.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - ezCater, Inc
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-11-21 00:00:00.000000000 Z
11
+ date: 2023-11-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -216,6 +216,7 @@ files:
216
216
  - lib/rubocop/cop/ezcater/direct_env_check.rb
217
217
  - lib/rubocop/cop/ezcater/feature_flag_active.rb
218
218
  - lib/rubocop/cop/ezcater/feature_flag_name_valid.rb
219
+ - lib/rubocop/cop/ezcater/graphql/not_authorized_scalar_field.rb
219
220
  - lib/rubocop/cop/ezcater/rails_configuration.rb
220
221
  - lib/rubocop/cop/ezcater/rails_env.rb
221
222
  - lib/rubocop/cop/ezcater/rails_top_level_sql_execute.rb