active_security 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,100 @@
1
+ module ActiveSecurity
2
+ # @guide begin
3
+ #
4
+ # ## Required Scope
5
+ #
6
+ # The {ActiveSecurity::Scoped} module allows ActiveSecurity to enforce querying
7
+ # within a scope.
8
+ #
9
+ # This allows, for example:
10
+ #
11
+ # class Restaurant < ActiveRecord::Base
12
+ # extend ActiveSecurity
13
+ # belongs_to :city
14
+ # active_security use: :scoped, scope: :city
15
+ # end
16
+ #
17
+ # class City < ActiveRecord::Base
18
+ # extend ActiveSecurity
19
+ # has_many :restaurants
20
+ # end
21
+ #
22
+ # City.find_by(name: "seattle").restaurants.restricted.find(23)
23
+ # City.find_by(name: "chicago").restaurants.restricted.find(23)
24
+ #
25
+ # The value for the `:scope` option can be the name of a `belongs_to` relation, or
26
+ # a column.
27
+ #
28
+ # Additionally, the `:scope` option can receive an array of scope values:
29
+ #
30
+ # class Cuisine < ActiveRecord::Base
31
+ # extend ActiveSecurity
32
+ # has_many :restaurants
33
+ # end
34
+ #
35
+ # class City < ActiveRecord::Base
36
+ # extend ActiveSecurity
37
+ # has_many :restaurants
38
+ # end
39
+ #
40
+ # class Restaurant < ActiveRecord::Base
41
+ # extend ActiveSecurity
42
+ # belongs_to :city
43
+ # active_security use: :scoped, scope: [:city, :cuisine]
44
+ # end
45
+ #
46
+ # All supplied values will be used to determine scope.
47
+ #
48
+ # ### Finding Records
49
+ #
50
+ # It's best to query through the relation:
51
+ #
52
+ # @city.restaurants.restricted.find(23)
53
+ #
54
+ # Alternatively, you could pass the scope value as a query parameter:
55
+ #
56
+ # Restaurant.where(city_id: @city.id).restricted.find(23)
57
+ #
58
+ # @guide end
59
+ module Scoped
60
+ class << self
61
+ # Sets up behavior and configuration options for scoped feature.
62
+ def included(model_class)
63
+ model_class.class_eval do
64
+ active_security_config.class.send(:include, Configuration)
65
+ end
66
+ end
67
+ end
68
+
69
+ # This module adds the `:scope` configuration option to
70
+ # {ActiveSecurity::Configuration ActiveSecurity::Configuration}.
71
+ module Configuration
72
+ # Gets the scope value.
73
+ #
74
+ # When setting this value, the argument should be a symbol referencing a
75
+ # `belongs_to` relation, or a column.
76
+ #
77
+ # @return Symbol The scope value
78
+ attr_accessor :scope
79
+
80
+ # Gets the scope columns.
81
+ #
82
+ # Checks to see if the `:scope` option passed to
83
+ # {ActiveSecurity::Base#active_security} refers to a relation, and if so, returns
84
+ # the relation's foreign key. Otherwise it assumes the option value was
85
+ # the name of column and returns it cast to a String.
86
+ #
87
+ # @return String The scope column
88
+ def scope_columns
89
+ [@scope].flatten.map { |s| (reflection_foreign_key(s) or s).to_s }
90
+ end
91
+
92
+ private
93
+
94
+ def reflection_foreign_key(scope)
95
+ reflection = model_class.reflections[scope] || model_class.reflections[scope.to_s]
96
+ reflection.try(:foreign_key)
97
+ end
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveSecurity
4
+ module Version
5
+ VERSION = "1.0.0"
6
+ end
7
+ end
@@ -0,0 +1,91 @@
1
+ # frozen_string_literal: true
2
+
3
+ # External Libraries
4
+ require "version_gem"
5
+ require "active_record"
6
+ require "active_support"
7
+
8
+ # This library
9
+ require_relative "active_security/version"
10
+ require_relative "active_security/base"
11
+ require_relative "active_security/configuration"
12
+ require_relative "active_security/finder_methods"
13
+ require_relative "active_security/privileged_hooks"
14
+ require_relative "active_security/restricted_hooks"
15
+
16
+ module ActiveSecurity
17
+ class RestrictedAccessError < RuntimeError; end
18
+
19
+ class UnhandledArelPredicateError < RuntimeError; end
20
+
21
+ class InvalidConfig < ArgumentError; end
22
+
23
+ autoload :Finders, "active_security/finders"
24
+ autoload :Privileged, "active_security/privileged"
25
+ autoload :Restricted, "active_security/restricted"
26
+ autoload :Scoped, "active_security/scoped"
27
+
28
+ class << self
29
+ # ActiveSecurity takes advantage of `extended` to do basic model setup, primarily
30
+ # extending {ActiveSecurity::Base} to add {ActiveSecurity::Base#active_security
31
+ # active_security} as a class method.
32
+ #
33
+ # In addition to adding {ActiveSecurity::Base#active_security active_security}, the class
34
+ # instance variable +@active_security_config+ is added. This variable is an
35
+ # instance of an anonymous subclass of {ActiveSecurity::Configuration}. This
36
+ # allows subsequently loaded modules like {ActiveSecurity::Scoped} to add
37
+ # functionality to the configuration class only for the current class,
38
+ # rather than monkey patching {ActiveSecurity::Configuration} directly.
39
+ # This isolates other models from large feature changes an addon to
40
+ # ActiveSecurity could potentially introduce.
41
+ #
42
+ # The upshot of this is, you can have two Active Record models that both have
43
+ # a @active_security_config, but each config object can have different methods
44
+ # and behaviors depending on what modules have been loaded, without
45
+ # conflicts. Keep this in mind if you're hacking on ActiveSecurity.
46
+ #
47
+ # For examples of this, see the source for {Scoped.included}.
48
+ def extended(model_class)
49
+ return if model_class.respond_to?(:active_security)
50
+ class << model_class
51
+ alias_method :relation_without_active_security, :relation
52
+ end
53
+ model_class.class_eval do
54
+ extend(Base)
55
+ @active_security_config = Class.new(Configuration).new(self) # rubocop:disable ThreadSafety/InstanceVariableInClassMethod
56
+ ActiveSecurity.defaults.call(@active_security_config) # rubocop:disable ThreadSafety/InstanceVariableInClassMethod
57
+ end
58
+ end
59
+
60
+ # Allow developers to `include` ActiveSecurity or `extend` it.
61
+ def included(model_class)
62
+ model_class.extend(self)
63
+ end
64
+
65
+ # Set global defaults for all models using ActiveSecurity.
66
+ #
67
+ # The default defaults are to use the `:restricted` module and nothing else.
68
+ #
69
+ # @example
70
+ # ActiveSecurity.defaults do |config|
71
+ # config.base :name
72
+ # config.use :something_else
73
+ # end
74
+ def defaults(&block)
75
+ @defaults = block if block # rubocop:disable ThreadSafety/InstanceVariableInClassMethod
76
+ @defaults ||= ->(config) { config.use(:restricted) } # rubocop:disable ThreadSafety/InstanceVariableInClassMethod
77
+ end
78
+
79
+ # If you need to reset the defaults to original defaults, just call without a block:
80
+ #
81
+ # ActiveSecurity.reset_defaults
82
+ #
83
+ def reset_defaults
84
+ @defaults = nil # rubocop:disable ThreadSafety/InstanceVariableInClassMethod
85
+ end
86
+ end
87
+ end
88
+
89
+ ActiveSecurity::Version.class_eval do
90
+ extend VersionGem::Basic
91
+ end
data.tar.gz.sig ADDED
Binary file
metadata ADDED
@@ -0,0 +1,394 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: active_security
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Peter Boling
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain:
11
+ - |
12
+ -----BEGIN CERTIFICATE-----
13
+ MIIEgDCCAuigAwIBAgIBATANBgkqhkiG9w0BAQsFADBDMRUwEwYDVQQDDAxwZXRl
14
+ ci5ib2xpbmcxFTATBgoJkiaJk/IsZAEZFgVnbWFpbDETMBEGCgmSJomT8ixkARkW
15
+ A2NvbTAeFw0yMzA5MjAxNzMwMjhaFw0yNDA5MTkxNzMwMjhaMEMxFTATBgNVBAMM
16
+ DHBldGVyLmJvbGluZzEVMBMGCgmSJomT8ixkARkWBWdtYWlsMRMwEQYKCZImiZPy
17
+ LGQBGRYDY29tMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEA+a9UvHo3
18
+ 84k96WgU5Kk5HB+cLZs/modjorsTfqY67MJF5nNvAoqcKTUBW4uG+Zpfnm3jaDO5
19
+ GxhJEIZWfndYzycHT2KMVQ1uTP82ba8ZaKrPlPIafkbui3mdds47qsmqHiblKERg
20
+ U532lkwfqHDlJwE7OBZQ59EwWWLynlT/yAUHpOBbqIuHKUxdpmBI+sIjrZcD1e05
21
+ WmjkO6fwIdC5oM757aoPxIgXD587VOViH11Vkm2doskj4T8yONtwVHlcrrhJ9Bzd
22
+ /zdp6vEn7GZQrABvpOlqwWxQ72ZnFhJe/RJZf6CXOPOh69Ai0QKYl2a1sYuCJKS3
23
+ nsBnxXJINEEznjR7rZjNUmYD+CZqfjzgPqedRxTlASe7iA4w7xZOqMDzcuhNwcUQ
24
+ tMEH6BTktxKP3jXZPXRfHCf6s+HRVb6vezAonTBVyydf5Xp5VwWkd6cwm+2BzHl5
25
+ 7kc/3lLxKMcsyEUprAsk8LdHohwZdC267l+RS++AP6Cz6x+nB3oGob19AgMBAAGj
26
+ fzB9MAkGA1UdEwQCMAAwCwYDVR0PBAQDAgSwMB0GA1UdDgQWBBQCSSas60GqqMjt
27
+ xR7LoY1gucEvtzAhBgNVHREEGjAYgRZwZXRlci5ib2xpbmdAZ21haWwuY29tMCEG
28
+ A1UdEgQaMBiBFnBldGVyLmJvbGluZ0BnbWFpbC5jb20wDQYJKoZIhvcNAQELBQAD
29
+ ggGBAMl9ifcw5p+PdvB7dCPoNKoVdp/2LbC9ztETHuYL2gUMJB6UoS3o9c/piSuR
30
+ V3ZMQaijmNu6ms1bWAtJ66LjmYrVflJtf9yp31Kierr9LpisMSUx2qbMOHGa8d2Z
31
+ vCUWPF8E9Cg0mP3GAyZ6qql8jDh/anUKeksPXqJvNxNPDu2DVYsa/IWdl96whzS4
32
+ Bl7SwB1E7agps40UcshCSKaVDOU0M+XN6SrnJMElnBic+KSAkBkVFbzS0BE4ODZM
33
+ BgE6nYzQ05qhuvbE+oGdACTlemNtDDWCh0uw+7x0q2PocGIDU5zsPn/WNTkCXPmB
34
+ CHGvqDNWq4M7ncTKAaS2XExgyb7uPdq9fKiOW8nmH+zCiGzJXzBWwZlKf7L4Ht9E
35
+ a3f0e5C+zvee9Z5Ng9ciyfav9/fcXgYt5MjoBv27THr5XfBhgOCIHSYW2tqJmWKi
36
+ KuxrfYrN+9HvMdm+nZ6TypmKftHY3Gj+/uu+g8Icm/zrvTWAEE0mcJOkfrIoNPJb
37
+ pF8dMA==
38
+ -----END CERTIFICATE-----
39
+ date: 2024-07-05 00:00:00.000000000 Z
40
+ dependencies:
41
+ - !ruby/object:Gem::Dependency
42
+ name: activerecord
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '7.0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '7.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: activesupport
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '7.0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '7.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: version_gem
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '1.1'
76
+ - - ">="
77
+ - !ruby/object:Gem::Version
78
+ version: 1.1.4
79
+ type: :runtime
80
+ prerelease: false
81
+ version_requirements: !ruby/object:Gem::Requirement
82
+ requirements:
83
+ - - "~>"
84
+ - !ruby/object:Gem::Version
85
+ version: '1.1'
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: 1.1.4
89
+ - !ruby/object:Gem::Dependency
90
+ name: rake
91
+ requirement: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ version: '13'
96
+ type: :development
97
+ prerelease: false
98
+ version_requirements: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - ">="
101
+ - !ruby/object:Gem::Version
102
+ version: '13'
103
+ - !ruby/object:Gem::Dependency
104
+ name: anonymous_active_record
105
+ requirement: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - "~>"
108
+ - !ruby/object:Gem::Version
109
+ version: '1.0'
110
+ - - ">="
111
+ - !ruby/object:Gem::Version
112
+ version: 1.0.8
113
+ type: :development
114
+ prerelease: false
115
+ version_requirements: !ruby/object:Gem::Requirement
116
+ requirements:
117
+ - - "~>"
118
+ - !ruby/object:Gem::Version
119
+ version: '1.0'
120
+ - - ">="
121
+ - !ruby/object:Gem::Version
122
+ version: 1.0.8
123
+ - !ruby/object:Gem::Dependency
124
+ name: appraisal
125
+ requirement: !ruby/object:Gem::Requirement
126
+ requirements:
127
+ - - "~>"
128
+ - !ruby/object:Gem::Version
129
+ version: '2.5'
130
+ type: :development
131
+ prerelease: false
132
+ version_requirements: !ruby/object:Gem::Requirement
133
+ requirements:
134
+ - - "~>"
135
+ - !ruby/object:Gem::Version
136
+ version: '2.5'
137
+ - !ruby/object:Gem::Dependency
138
+ name: rspec
139
+ requirement: !ruby/object:Gem::Requirement
140
+ requirements:
141
+ - - ">="
142
+ - !ruby/object:Gem::Version
143
+ version: '3'
144
+ type: :development
145
+ prerelease: false
146
+ version_requirements: !ruby/object:Gem::Requirement
147
+ requirements:
148
+ - - ">="
149
+ - !ruby/object:Gem::Version
150
+ version: '3'
151
+ - !ruby/object:Gem::Dependency
152
+ name: rspec-block_is_expected
153
+ requirement: !ruby/object:Gem::Requirement
154
+ requirements:
155
+ - - "~>"
156
+ - !ruby/object:Gem::Version
157
+ version: '1.0'
158
+ - - ">="
159
+ - !ruby/object:Gem::Version
160
+ version: 1.0.5
161
+ type: :development
162
+ prerelease: false
163
+ version_requirements: !ruby/object:Gem::Requirement
164
+ requirements:
165
+ - - "~>"
166
+ - !ruby/object:Gem::Version
167
+ version: '1.0'
168
+ - - ">="
169
+ - !ruby/object:Gem::Version
170
+ version: 1.0.5
171
+ - !ruby/object:Gem::Dependency
172
+ name: rspec-pending_for
173
+ requirement: !ruby/object:Gem::Requirement
174
+ requirements:
175
+ - - "~>"
176
+ - !ruby/object:Gem::Version
177
+ version: '0.1'
178
+ - - ">="
179
+ - !ruby/object:Gem::Version
180
+ version: 0.1.16
181
+ type: :development
182
+ prerelease: false
183
+ version_requirements: !ruby/object:Gem::Requirement
184
+ requirements:
185
+ - - "~>"
186
+ - !ruby/object:Gem::Version
187
+ version: '0.1'
188
+ - - ">="
189
+ - !ruby/object:Gem::Version
190
+ version: 0.1.16
191
+ - !ruby/object:Gem::Dependency
192
+ name: silent_stream
193
+ requirement: !ruby/object:Gem::Requirement
194
+ requirements:
195
+ - - "~>"
196
+ - !ruby/object:Gem::Version
197
+ version: '1.0'
198
+ - - ">="
199
+ - !ruby/object:Gem::Version
200
+ version: 1.0.8
201
+ type: :development
202
+ prerelease: false
203
+ version_requirements: !ruby/object:Gem::Requirement
204
+ requirements:
205
+ - - "~>"
206
+ - !ruby/object:Gem::Version
207
+ version: '1.0'
208
+ - - ">="
209
+ - !ruby/object:Gem::Version
210
+ version: 1.0.8
211
+ - !ruby/object:Gem::Dependency
212
+ name: sqlite3
213
+ requirement: !ruby/object:Gem::Requirement
214
+ requirements:
215
+ - - ">="
216
+ - !ruby/object:Gem::Version
217
+ version: 1.6.9
218
+ - - "<"
219
+ - !ruby/object:Gem::Version
220
+ version: '2'
221
+ type: :development
222
+ prerelease: false
223
+ version_requirements: !ruby/object:Gem::Requirement
224
+ requirements:
225
+ - - ">="
226
+ - !ruby/object:Gem::Version
227
+ version: 1.6.9
228
+ - - "<"
229
+ - !ruby/object:Gem::Version
230
+ version: '2'
231
+ - !ruby/object:Gem::Dependency
232
+ name: kettle-soup-cover
233
+ requirement: !ruby/object:Gem::Requirement
234
+ requirements:
235
+ - - "~>"
236
+ - !ruby/object:Gem::Version
237
+ version: '1.0'
238
+ - - ">="
239
+ - !ruby/object:Gem::Version
240
+ version: 1.0.2
241
+ type: :development
242
+ prerelease: false
243
+ version_requirements: !ruby/object:Gem::Requirement
244
+ requirements:
245
+ - - "~>"
246
+ - !ruby/object:Gem::Version
247
+ version: '1.0'
248
+ - - ">="
249
+ - !ruby/object:Gem::Version
250
+ version: 1.0.2
251
+ - !ruby/object:Gem::Dependency
252
+ name: rubocop-lts
253
+ requirement: !ruby/object:Gem::Requirement
254
+ requirements:
255
+ - - "~>"
256
+ - !ruby/object:Gem::Version
257
+ version: '18.2'
258
+ - - ">="
259
+ - !ruby/object:Gem::Version
260
+ version: 18.2.1
261
+ type: :development
262
+ prerelease: false
263
+ version_requirements: !ruby/object:Gem::Requirement
264
+ requirements:
265
+ - - "~>"
266
+ - !ruby/object:Gem::Version
267
+ version: '18.2'
268
+ - - ">="
269
+ - !ruby/object:Gem::Version
270
+ version: 18.2.1
271
+ - !ruby/object:Gem::Dependency
272
+ name: rubocop-packaging
273
+ requirement: !ruby/object:Gem::Requirement
274
+ requirements:
275
+ - - "~>"
276
+ - !ruby/object:Gem::Version
277
+ version: '0.5'
278
+ - - ">="
279
+ - !ruby/object:Gem::Version
280
+ version: 0.5.2
281
+ type: :development
282
+ prerelease: false
283
+ version_requirements: !ruby/object:Gem::Requirement
284
+ requirements:
285
+ - - "~>"
286
+ - !ruby/object:Gem::Version
287
+ version: '0.5'
288
+ - - ">="
289
+ - !ruby/object:Gem::Version
290
+ version: 0.5.2
291
+ - !ruby/object:Gem::Dependency
292
+ name: rubocop-rspec
293
+ requirement: !ruby/object:Gem::Requirement
294
+ requirements:
295
+ - - "~>"
296
+ - !ruby/object:Gem::Version
297
+ version: '2.10'
298
+ type: :development
299
+ prerelease: false
300
+ version_requirements: !ruby/object:Gem::Requirement
301
+ requirements:
302
+ - - "~>"
303
+ - !ruby/object:Gem::Version
304
+ version: '2.10'
305
+ - !ruby/object:Gem::Dependency
306
+ name: yard
307
+ requirement: !ruby/object:Gem::Requirement
308
+ requirements:
309
+ - - "~>"
310
+ - !ruby/object:Gem::Version
311
+ version: '0.9'
312
+ - - ">="
313
+ - !ruby/object:Gem::Version
314
+ version: 0.9.34
315
+ type: :development
316
+ prerelease: false
317
+ version_requirements: !ruby/object:Gem::Requirement
318
+ requirements:
319
+ - - "~>"
320
+ - !ruby/object:Gem::Version
321
+ version: '0.9'
322
+ - - ">="
323
+ - !ruby/object:Gem::Version
324
+ version: 0.9.34
325
+ - !ruby/object:Gem::Dependency
326
+ name: yard-junk
327
+ requirement: !ruby/object:Gem::Requirement
328
+ requirements:
329
+ - - "~>"
330
+ - !ruby/object:Gem::Version
331
+ version: '0.0'
332
+ type: :development
333
+ prerelease: false
334
+ version_requirements: !ruby/object:Gem::Requirement
335
+ requirements:
336
+ - - "~>"
337
+ - !ruby/object:Gem::Version
338
+ version: '0.0'
339
+ description: Disallow insecure, unscoped, finds
340
+ email:
341
+ - peter.boling@gmail.com
342
+ executables: []
343
+ extensions: []
344
+ extra_rdoc_files: []
345
+ files:
346
+ - CHANGELOG.md
347
+ - CODE_OF_CONDUCT.md
348
+ - CONTRIBUTING.md
349
+ - LICENSE.txt
350
+ - README.md
351
+ - SECURITY.md
352
+ - lib/active_security.rb
353
+ - lib/active_security/base.rb
354
+ - lib/active_security/configuration.rb
355
+ - lib/active_security/finder_methods.rb
356
+ - lib/active_security/finders.rb
357
+ - lib/active_security/privileged.rb
358
+ - lib/active_security/privileged_hooks.rb
359
+ - lib/active_security/restricted.rb
360
+ - lib/active_security/restricted_hooks.rb
361
+ - lib/active_security/scoped.rb
362
+ - lib/active_security/version.rb
363
+ homepage: https://github.com/pboling/active_security
364
+ licenses:
365
+ - MIT
366
+ metadata:
367
+ homepage_uri: https://github.com/pboling/active_security
368
+ source_code_uri: https://github.com/pboling/active_security/tree/v1.0.0
369
+ changelog_uri: https://github.com/pboling/active_security/blob/v1.0.0/CHANGELOG.md
370
+ bug_tracker_uri: https://github.com/pboling/active_security/issues
371
+ documentation_uri: https://www.rubydoc.info/gems/active_security/1.0.0
372
+ wiki_uri: https://github.com/pboling/active_security/wiki
373
+ funding_uri: https://liberapay.com/pboling
374
+ rubygems_mfa_required: 'true'
375
+ post_install_message:
376
+ rdoc_options: []
377
+ require_paths:
378
+ - lib
379
+ required_ruby_version: !ruby/object:Gem::Requirement
380
+ requirements:
381
+ - - ">="
382
+ - !ruby/object:Gem::Version
383
+ version: 2.7.0
384
+ required_rubygems_version: !ruby/object:Gem::Requirement
385
+ requirements:
386
+ - - ">="
387
+ - !ruby/object:Gem::Version
388
+ version: '0'
389
+ requirements: []
390
+ rubygems_version: 3.5.14
391
+ signing_key:
392
+ specification_version: 4
393
+ summary: Prevent insecure, unscoped, finds
394
+ test_files: []
metadata.gz.sig ADDED
Binary file