ezcater_rubocop 6.0.3 → 6.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 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