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 +4 -4
- data/CHANGELOG.md +5 -0
- data/README.md +46 -0
- data/config/default.yml +8 -0
- data/lib/ezcater_rubocop/version.rb +1 -1
- data/lib/ezcater_rubocop.rb +1 -0
- data/lib/rubocop/cop/ezcater/graphql/not_authorized_scalar_field.rb +198 -0
- metadata +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ae4de56eb716caa74ed16c478e3b727fe7a6d4b8bd5d2cdf3ff69900a270b22b
|
|
4
|
+
data.tar.gz: acc031ba45d8fd09ec70dd131ad8e6948d31cd187b39819ce5923c8462fde004
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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
|
data/lib/ezcater_rubocop.rb
CHANGED
|
@@ -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
|
|
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-
|
|
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
|