mongoid 9.0.12 → 9.0.13

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: 066d78f8b736bad08756e737ff7c0e1d0af9b97149366fc0b5b0a5997c3f1a63
4
- data.tar.gz: b55ea0b166bd8d9a0f465e88507ee8db2c4cccc7166477aec4b07a94d98c0a43
3
+ metadata.gz: 030d90a4693fc5b3ccb72a7069ce6dc912089351df98fd04ead3595a414433a0
4
+ data.tar.gz: 10362c8758cb9ec1e535b9940eab11088261e7cf4831b8a07bfffb6be231e8df
5
5
  SHA512:
6
- metadata.gz: 9e6529d35d0fba7786a830bec9ffc87937580c414d6925c5c14f3c799ea03599592ad943783690a29e24ae09f706b6462e42ec1058bd316a023c51d7467c457e
7
- data.tar.gz: 6625aaf9412d9ef3e5141b06a019bc83c33446612c3c1b16361473fb5a3ac1a006e2f4d3c6cdf0daa36c0b2b4ee2a9702b135b380011226f219517a578e203ac
6
+ metadata.gz: 8e5d6bfa84e64cd80f756e55d6fe846f10b5a820c79881b26a54c305f08fb02ef98d27990d7b51b595342844b38c11e04b6e9be911cd3306748c023d226bf9a2
7
+ data.tar.gz: 5a92a5485360f68cea7bbfa48259f0441f0df723d634926230c80b78784e6f8719083b3fef9d81537223b0da8f2b96563c8d267c4bbe9a372c592b781163fe45
@@ -239,6 +239,13 @@ en:
239
239
  Mongoid does not support."
240
240
  resolution: "Valid field operators are: %{valid_operators}.
241
241
  Ensure you are using one of these operators."
242
+ invalid_encryption_schema:
243
+ message: "The encryption schema for %{namespace} is invalid."
244
+ summary: "Two models writing to %{namespace} describe %{path}
245
+ differently. The encryption schema has one entry per namespace,
246
+ so the two descriptions cannot both be used."
247
+ resolution: "Make the models agree on the encryption options of the
248
+ conflicting field, or store them in different collections."
242
249
  invalid_estimated_count_criteria:
243
250
  message: "Invalid criteria for estimated_count."
244
251
  summary: "Estimated count is strictly a collection-level operation and cannot be called
@@ -544,22 +551,35 @@ en:
544
551
  no_encryption_schema:
545
552
  message: "The encryption schema of client %{client} does not cover
546
553
  %{namespace}."
547
- summary: "%{klass} declares encrypted fields, but the namespace it
548
- resolved to, %{namespace}, is not part of the automatic encryption
549
- schema of client %{client}. The encryption schema is built once,
550
- when the client is created, and is keyed by namespace, so a
551
- database name that is only known later - a callable :database
552
- option, Model.with(database:), Mongoid.override_database - is not
553
- in it. Routing the model to a client that has no
554
- auto_encryption_options has the same effect. Mongoid refuses the
555
- operation because the driver would store the declared fields in
556
- plaintext without reporting an error."
554
+ summary: "%{klass} declares encrypted fields, directly or through
555
+ an embedded model, but the namespace it resolved to, %{namespace},
556
+ is not part of the automatic encryption schema of client
557
+ %{client}. The encryption schema is built once, when the client
558
+ is created, and is keyed by namespace, so a database name that is
559
+ only known later - a callable :database option,
560
+ Model.with(database:), Mongoid.override_database - is not in it.
561
+ The same happens when an embedded model with encrypted fields was
562
+ not yet loaded when the client was created. Routing the model to a
563
+ client that has no auto_encryption_options has the same effect.
564
+ Mongoid refuses the operation because the driver would store the
565
+ declared fields in plaintext without reporting an error."
557
566
  resolution: "Give the model a namespace that is known when the
558
567
  client is created, and a client configured with
559
- auto_encryption_options. If the model has to live in a database
568
+ auto_encryption_options. Load all models, including embedded
569
+ ones, before the first client is created, for example by
570
+ preloading them at boot. If the model has to live in a database
560
571
  chosen at runtime, configure one client per database, each with
561
572
  its own auto_encryption_options, and select between them with
562
573
  Model.with(client:) instead of switching the database."
574
+ no_encryption_schema_field:
575
+ message: "The encryption schema of client %{client} does not cover
576
+ the field %{field} of %{namespace}."
577
+ summary: "The namespace %{namespace} is in the automatic encryption
578
+ schema of client %{client}, but its entry does not encrypt
579
+ %{field}, which %{klass} declares as encrypted. Mongoid refuses
580
+ the operation rather than storing the field in plaintext."
581
+ resolution: "Regenerate the schema map of the client, or add
582
+ %{field} to the schema entry for %{namespace}."
563
583
  no_map_reduce_output:
564
584
  message: "No output location was specified for the map/reduce
565
585
  operation."
@@ -138,6 +138,14 @@ module Mongoid
138
138
  _base.collect_children.each do |child|
139
139
  child.delayed_atomic_sets.clear
140
140
  end
141
+
142
+ # If the base document is itself inserted wholesale via a $set of
143
+ # its atomic path, that $set already contains these documents, and
144
+ # a nested $set under the same path would conflict with it. The
145
+ # cleanup above has already cleared the delayed sets the assigned
146
+ # children recorded, so skipping the recording here is safe.
147
+ return if _base.settable?
148
+
141
149
  _base.delayed_atomic_sets[path] = sets
142
150
  end
143
151
  end
@@ -91,6 +91,8 @@ module Mongoid
91
91
  return nil unless opts[:auto_encryption_options]
92
92
 
93
93
  opts[:auto_encryption_options].dup.tap do |auto_encryption_options|
94
+ Mongoid::Warnings.warn_bypass_auto_encryption if auto_encryption_options[:bypass_auto_encryption]
95
+
94
96
  if auto_encryption_options.key?(:schema_map)
95
97
  default_logger.warn(
96
98
  'The :schema_map is configured in the :auto_encryption_options for the client;' +
@@ -21,7 +21,11 @@ module Mongoid
21
21
  #
22
22
  # @return [ Hash ] The encryption schema map.
23
23
  def encryption_schema_map(default_database, models = ::Mongoid.models)
24
- models.each_with_object({}) do |model, map|
24
+ # Subclasses share their parent's collection but are not registered in
25
+ # Mongoid.models, so they have to be added to the walk explicitly.
26
+ classes = models.flat_map { |model| [ model ] + model.descendants }.uniq
27
+
28
+ classes.each_with_object({}) do |model, map|
25
29
  next if model.embedded?
26
30
  next unless model.requires_encryption_schema?
27
31
 
@@ -35,14 +39,33 @@ module Mongoid
35
39
  next if database.respond_to?(:call)
36
40
 
37
41
  key = "#{database}.#{model.collection_name}"
38
- props = metadata_for(model).merge(properties_for(model, [ model ]))
42
+ props = metadata_for(model).merge(properties_for(model, [ model ], key))
43
+ next if props.empty?
44
+
39
45
  # The root of a collection schema describes the document, so it is
40
46
  # always an object. Saying so matters when a nested schema carries
41
47
  # encryptMetadata: mongocryptd rejects the schema otherwise.
42
- map[key] = { 'bsonType' => 'object' }.merge(props) unless props.empty?
48
+ entry = { 'bsonType' => 'object' }.merge(props)
49
+ map[key] = map.key?(key) ? merge_schema_entries(map[key], entry, key) : entry
43
50
  end
44
51
  end
45
52
 
53
+ # Collect the paths of the fields encrypted by the schema generated for
54
+ # a single model.
55
+ #
56
+ # @param [ Mongoid::Document ] model The model.
57
+ #
58
+ # @return [ Array<Array<String>> ] The property paths, outermost first.
59
+ #
60
+ # @api private
61
+ def encrypted_paths_for(model)
62
+ return model.instance_variable_get(:@encrypted_paths_for) if
63
+ model.instance_variable_defined?(:@encrypted_paths_for)
64
+
65
+ properties = properties_for(model, [ model ])['properties'] || {}
66
+ model.instance_variable_set(:@encrypted_paths_for, collect_encrypted_paths(properties, []))
67
+ end
68
+
46
69
  private
47
70
 
48
71
  # The algorithm to use for the deterministic encryption.
@@ -110,10 +133,12 @@ module Mongoid
110
133
  # @param [ Mongoid::Document ] model The model to generate the properties for.
111
134
  # @param [ Array<Mongoid::Document> ] path The models the walk is already
112
135
  # inside of, outermost first.
136
+ # @param [ String | nil ] namespace The namespace the schema is built
137
+ # for, used for error reporting.
113
138
  #
114
139
  # @return [ Hash ] The encryption properties.
115
- def properties_for(model, path)
116
- result = properties_for_fields(model).merge(properties_for_relations(model, path))
140
+ def properties_for(model, path, namespace = nil)
141
+ result = properties_for_fields(model).merge(properties_for_relations(model, path, namespace))
117
142
  if result.empty?
118
143
  {}
119
144
  else
@@ -152,9 +177,11 @@ module Mongoid
152
177
  # @param [ Mongoid::Document ] model The model to generate the properties for.
153
178
  # @param [ Array<Mongoid::Document> ] path The models the walk is already
154
179
  # inside of, outermost first.
180
+ # @param [ String | nil ] namespace The namespace the schema is built
181
+ # for, used for error reporting.
155
182
  #
156
183
  # @return [ Hash ] The encryption properties.
157
- def properties_for_relations(model, path)
184
+ def properties_for_relations(model, path, namespace = nil)
158
185
  model.relations.each_with_object({}) do |(name, relation), props|
159
186
  # relation_class constantizes, and a polymorphic embedded_in has no
160
187
  # class to resolve, so the relation type has to be checked first.
@@ -164,21 +191,125 @@ module Mongoid
164
191
  # An association target does not have to be a Mongoid document, and
165
192
  # the class it names does not have to exist.
166
193
  next unless klass.respond_to?(:requires_encryption_schema?)
167
- # Stop at a model the walk is already inside of, or a self-embedding
168
- # model never terminates. The path covers the current branch only:
169
- # a model embedded by two parents, or twice by one parent, has to be
170
- # emitted at every place it appears.
171
- next if path.include?(klass)
172
- next unless klass.requires_encryption_schema?
173
-
174
- metadata_for(klass).merge(
175
- properties_for(klass, path + [ klass ])
176
- ).tap do |properties|
177
- props[name] = { 'bsonType' => 'object' }.merge(properties) unless properties.empty?
194
+
195
+ # Any subclass of the declared class can be assigned to the
196
+ # association, so its encrypted fields have to be mapped here too.
197
+ properties = ([ klass ] + klass.descendants).uniq.inject({}) do |merged, candidate|
198
+ # Stop at a model the walk is already inside of, or a self-embedding
199
+ # model never terminates. The path covers the current branch only:
200
+ # a model embedded by two parents, or twice by one parent, has to be
201
+ # emitted at every place it appears.
202
+ next merged if path.include?(candidate)
203
+ next merged unless candidate.respond_to?(:requires_encryption_schema?)
204
+ next merged unless candidate.requires_encryption_schema?
205
+
206
+ merge_schema_entries(
207
+ merged,
208
+ metadata_for(candidate).merge(
209
+ properties_for(candidate, path + [ candidate ], namespace)
210
+ ),
211
+ namespace
212
+ )
178
213
  end
214
+ props[name] = { 'bsonType' => 'object' }.merge(properties) unless properties.empty?
179
215
  end
180
216
  end
181
217
 
218
+ # Walk the schema properties and collect the path of every encrypted
219
+ # leaf.
220
+ #
221
+ # @param [ Hash ] properties The properties to walk.
222
+ # @param [ Array<String> ] path The properties the walk is already
223
+ # inside of.
224
+ #
225
+ # @return [ Array<Array<String>> ] The property paths.
226
+ def collect_encrypted_paths(properties, path)
227
+ properties.each_with_object([]) do |(name, schema), paths|
228
+ if schema.key?('encrypt')
229
+ paths << (path + [ name ])
230
+ elsif schema['properties']
231
+ paths.concat(collect_encrypted_paths(schema['properties'], path + [ name ]))
232
+ end
233
+ end
234
+ end
235
+
236
+ # Merge two schema objects covering the same model or namespace.
237
+ #
238
+ # Every model writing to one namespace contributes an entry to the
239
+ # schema map. Those entries have to agree on everything they have in
240
+ # common, or the schema would silently encrypt a field differently for
241
+ # one model than for another.
242
+ #
243
+ # @param [ Hash ] left The first schema.
244
+ # @param [ Hash ] right The second schema.
245
+ # @param [ String | nil ] namespace The namespace the schema belongs to.
246
+ #
247
+ # @return [ Hash ] The merged schema.
248
+ def merge_schema_entries(left, right, namespace = nil)
249
+ left.merge(right) do |key, left_value, right_value|
250
+ case key
251
+ when 'bsonType'
252
+ left_value
253
+ when 'encryptMetadata'
254
+ merge_encrypt_metadata(left_value, right_value, namespace)
255
+ when 'properties'
256
+ merge_properties(left_value, right_value, namespace)
257
+ else
258
+ raise_invalid_encryption_schema(namespace, key)
259
+ end
260
+ end
261
+ end
262
+
263
+ # Merge two encryptMetadata objects.
264
+ #
265
+ # @param [ Hash ] left The first encryptMetadata object.
266
+ # @param [ Hash ] right The second encryptMetadata object.
267
+ # @param [ String | nil ] namespace The namespace the schema belongs to.
268
+ #
269
+ # @return [ Hash ] The merged encryptMetadata object.
270
+ def merge_encrypt_metadata(left, right, namespace)
271
+ left.merge(right) do |key, left_value, right_value|
272
+ unless left_value == right_value
273
+ raise_invalid_encryption_schema(namespace, "encryptMetadata.#{key}")
274
+ end
275
+
276
+ left_value
277
+ end
278
+ end
279
+
280
+ # Merge two properties objects.
281
+ #
282
+ # @param [ Hash ] left The first properties object.
283
+ # @param [ Hash ] right The second properties object.
284
+ # @param [ String | nil ] namespace The namespace the schema belongs to.
285
+ #
286
+ # @return [ Hash ] The merged properties object.
287
+ def merge_properties(left, right, namespace)
288
+ left.merge(right) do |name, left_value, right_value|
289
+ if left_value.key?('encrypt') && right_value.key?('encrypt')
290
+ unless left_value['encrypt'] == right_value['encrypt']
291
+ raise_invalid_encryption_schema(namespace, "properties.#{name}")
292
+ end
293
+
294
+ left_value
295
+ elsif left_value.key?('encrypt') || right_value.key?('encrypt')
296
+ raise_invalid_encryption_schema(namespace, "properties.#{name}")
297
+ else
298
+ merge_schema_entries(left_value, right_value, namespace)
299
+ end
300
+ end
301
+ end
302
+
303
+ # Raise an error for a schema conflicting with another one.
304
+ #
305
+ # @param [ String | nil ] namespace The namespace the schema belongs to.
306
+ # @param [ String ] path The conflicting path in the schema.
307
+ #
308
+ # @raise [ Errors::InvalidEncryptionSchema ] Always raised.
309
+ def raise_invalid_encryption_schema(namespace, path)
310
+ raise Errors::InvalidEncryptionSchema.new(namespace, path)
311
+ end
312
+
182
313
  # Get the BSON type identifier for the provided field according to the
183
314
  # https://www.mongodb.com/docs/manual/reference/bson-types/#std-label-bson-types
184
315
  #
@@ -44,21 +44,29 @@ module Mongoid
44
44
  # group has no encrypted field of its own, but its collection still needs
45
45
  # a schema, otherwise the embedded fields are written in plaintext.
46
46
  #
47
- # The answer is memoized, since this runs on the persistence path.
48
- # Declaring encryption on a model after it has already been persisted is
49
- # not supported.
47
+ # This runs on the persistence path, so the answer is memoized. A true
48
+ # answer is always memoized. A false answer is memoized only when every
49
+ # embeds_one target in the walk resolved to a class; if one could not be
50
+ # resolved yet, the answer is recomputed next time, so a class loaded
51
+ # later is still detected. Declaring encryption on a model after it has
52
+ # already been persisted is not supported.
50
53
  #
51
54
  # @return [ true | false ] Whether the model needs an encryption schema.
52
55
  #
53
56
  # @api private
54
57
  def requires_encryption_schema?
55
58
  return @requires_encryption_schema if defined?(@requires_encryption_schema)
59
+ return @requires_encryption_schema = true if encrypted?
56
60
 
57
- @requires_encryption_schema = encrypted? || embeds_encrypted?([ self ])
61
+ found, complete = embedded_encryption_scan([ self ])
62
+ @requires_encryption_schema = found if found || complete
63
+ found
58
64
  end
59
65
 
60
- # Whether any model reachable through this model's embeds_one relations
61
- # declares encryption.
66
+ # Walks the models reachable through this model's embeds_one relations,
67
+ # looking for one that declares encryption. Subclasses of an
68
+ # association target are included: any of them can be assigned to the
69
+ # association.
62
70
  #
63
71
  # embeds_many is not considered: libmongocrypt cannot express per-field
64
72
  # encryption under array items, so those fields are never mapped.
@@ -66,21 +74,40 @@ module Mongoid
66
74
  # @param [ Array<Class> ] path The models the walk is already inside of.
67
75
  # A model embedding itself terminates here.
68
76
  #
69
- # @return [ true | false ] Whether an embedded model is encrypted.
77
+ # @return [ Array<true | false> ] A pair: whether an embedded model is
78
+ # encrypted, and whether every embeds_one target the walk needed
79
+ # resolved to a class. The second value is only meaningful when the
80
+ # first is false.
70
81
  #
71
82
  # @api private
72
- def embeds_encrypted?(path)
73
- relations.each_value.any? do |relation|
74
- next false unless relation.is_a?(Association::Embedded::EmbedsOne)
83
+ def embedded_encryption_scan(path)
84
+ complete = true
85
+
86
+ relations.each_value do |relation|
87
+ next unless relation.is_a?(Association::Embedded::EmbedsOne)
75
88
 
76
89
  klass = relation.try_relation_class
77
- # An association target does not have to be a Mongoid document, and
78
- # the class it names does not have to exist.
79
- next false unless klass.respond_to?(:encrypted?)
80
- next false if path.include?(klass)
90
+ # The class an association names does not have to exist yet.
91
+ if klass.nil?
92
+ complete = false
93
+ next
94
+ end
95
+
96
+ # An association target does not have to be a Mongoid document.
97
+ next unless klass.respond_to?(:encrypted?)
98
+
99
+ ([ klass ] + klass.descendants).uniq.each do |candidate|
100
+ next if path.include?(candidate)
101
+ return [ true, true ] if candidate.encrypted?
81
102
 
82
- klass.encrypted? || klass.embeds_encrypted?(path + [ klass ])
103
+ found, nested_complete = candidate.embedded_encryption_scan(path + [ candidate ])
104
+ return [ true, true ] if found
105
+
106
+ complete &&= nested_complete
107
+ end
83
108
  end
109
+
110
+ [ false, complete ]
84
111
  end
85
112
 
86
113
  # Override the key_id for the model.
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mongoid
4
+ module Errors
5
+ # This error is raised when two models writing to the same namespace
6
+ # describe a field, or the collection metadata, differently. The schema map
7
+ # has one entry per namespace, so the two descriptions cannot both be
8
+ # honored.
9
+ class InvalidEncryptionSchema < MongoidError
10
+ # Create the new error.
11
+ #
12
+ # @example Create the error.
13
+ # InvalidEncryptionSchema.new('music.bands', 'properties.code')
14
+ #
15
+ # @param [ String | nil ] namespace The namespace being described.
16
+ # @param [ String ] path The conflicting path in the schema.
17
+ def initialize(namespace, path)
18
+ super(
19
+ compose_message(
20
+ 'invalid_encryption_schema',
21
+ { namespace: namespace || 'the collection', path: path }
22
+ )
23
+ )
24
+ end
25
+ end
26
+ end
27
+ end
@@ -15,11 +15,13 @@ module Mongoid
15
15
  # @param [ Class ] klass The model class.
16
16
  # @param [ String ] namespace The namespace the model resolved to.
17
17
  # @param [ String | Symbol ] client The name of the client in use.
18
- def initialize(klass, namespace, client)
18
+ # @param [ String | nil ] field The encrypted field missing from the
19
+ # schema entry, if the namespace itself is covered.
20
+ def initialize(klass, namespace, client, field = nil)
19
21
  super(
20
22
  compose_message(
21
- 'no_encryption_schema',
22
- { klass: klass, namespace: namespace, client: client }
23
+ field ? 'no_encryption_schema_field' : 'no_encryption_schema',
24
+ { klass: klass, namespace: namespace, client: client, field: field }
23
25
  )
24
26
  )
25
27
  end
@@ -20,6 +20,7 @@ require "mongoid/errors/invalid_collection"
20
20
  require "mongoid/errors/invalid_config_file"
21
21
  require "mongoid/errors/invalid_config_option"
22
22
  require "mongoid/errors/invalid_dependent_strategy"
23
+ require "mongoid/errors/invalid_encryption_schema"
23
24
  require "mongoid/errors/invalid_field"
24
25
  require "mongoid/errors/invalid_field_option"
25
26
  require "mongoid/errors/invalid_field_type"
@@ -209,12 +209,15 @@ module Mongoid
209
209
  # that schema, and when it is absent it asks the server for a schema
210
210
  # instead; a collection without a validator then yields no encryption at
211
211
  # all, and no error. Checking the namespace here is what turns that silent
212
- # downgrade into a failure.
212
+ # downgrade into a failure. When the namespace is present, its entry is
213
+ # checked against the fields the model declares as encrypted too: a
214
+ # hand-written schema can cover the namespace and still leave out a field.
213
215
  #
214
216
  # @param [ Mongo::Client ] client The client this context resolved to.
215
217
  #
216
218
  # @raise [ Errors::NoEncryptionSchema ] if the model needs an encryption
217
- # schema and the client's schema does not cover the target namespace.
219
+ # schema and the client's schema does not cover the target namespace, or
220
+ # the namespace entry does not cover every encrypted field of the model.
218
221
  def verify_encryption_schema!(client)
219
222
  klass = @object.is_a?(Class) ? @object : @object.class
220
223
  # A model whose encrypted fields all live on embedded models declares no
@@ -229,9 +232,48 @@ module Mongoid
229
232
 
230
233
  schema_map = client.options.dig(:auto_encryption_options, :schema_map)
231
234
  namespace = "#{client.database.name}.#{collection_name}"
232
- return if schema_map&.key?(namespace)
235
+ entry = schema_map && schema_map[namespace]
236
+ raise Errors::NoEncryptionSchema.new(klass, namespace, client_name) unless entry
233
237
 
234
- raise Errors::NoEncryptionSchema.new(klass, namespace, client_name)
238
+ # The schema map may have been written by hand, with symbol keys rather
239
+ # than strings; both are tolerated at every level.
240
+ Mongoid.config.encrypted_paths_for(klass).each do |path|
241
+ next if encryption_schema_has_path?(entry, path)
242
+
243
+ raise Errors::NoEncryptionSchema.new(
244
+ klass, namespace, client_name, path.join('.')
245
+ )
246
+ end
247
+ end
248
+
249
+ # Whether a schema entry encrypts the property at the given path.
250
+ #
251
+ # @param [ Hash ] entry The namespace schema entry.
252
+ # @param [ Array<String> ] path The property path, outermost first.
253
+ #
254
+ # @return [ true | false ] Whether the leaf is marked as encrypted.
255
+ def encryption_schema_has_path?(entry, path)
256
+ node = entry
257
+ path.each do |name|
258
+ properties = schema_value(node, 'properties')
259
+ return false unless properties.is_a?(Hash)
260
+
261
+ node = schema_value(properties, name)
262
+ return false unless node.is_a?(Hash)
263
+ end
264
+ !schema_value(node, 'encrypt').nil?
265
+ end
266
+
267
+ # Read a schema key that may be written as a string or a symbol.
268
+ #
269
+ # @param [ Hash ] hash The schema object.
270
+ # @param [ String ] key The key to read.
271
+ #
272
+ # @return [ Object ] The value, or nil when the key is absent.
273
+ def schema_value(hash, key)
274
+ return hash[key] if hash.key?(key)
275
+
276
+ hash[key.to_sym]
235
277
  end
236
278
 
237
279
  def client_options
@@ -167,7 +167,11 @@ module Mongoid
167
167
  #
168
168
  # @return [ Array<Hash> ] the raw index documents
169
169
  def get_indexes(names)
170
- collection.search_indexes.select { |i| names.include?(i['name']) }
170
+ # Reading index metadata sends no document data, so it is exempt from
171
+ # the encryption schema check, like the other index operations here.
172
+ Threaded.with_collection_management do
173
+ collection.search_indexes.select { |i| names.include?(i['name']) }
174
+ end
171
175
  end
172
176
  end
173
177
  end
@@ -65,15 +65,18 @@ module Mongoid
65
65
  # @param [ true | false ] wait whether to wait for the indexes to be
66
66
  # built.
67
67
  def create_search_indexes(models = ::Mongoid.models, wait: true)
68
- searchable = models.select { |m| m.search_index_specs.any? }
68
+ Threaded.with_collection_management do
69
+ searchable = models.select { |m| m.search_index_specs.any? }
69
70
 
70
- # queue up the search index creation requests
71
- index_names_by_model = searchable.each_with_object({}) do |model, obj|
72
- logger.info("MONGOID: Creating search indexes on #{model}...")
73
- obj[model] = model.create_search_indexes
74
- end
71
+ # queue up the search index creation requests
72
+ index_names_by_model = searchable.each_with_object({}) do |model, obj|
73
+ logger.info("MONGOID: Creating search indexes on #{model}...")
74
+ obj[model] = model.create_search_indexes
75
+ end
75
76
 
76
- wait_for_search_indexes(index_names_by_model) if wait
77
+ wait_for_search_indexes(index_names_by_model) if wait
78
+ index_names_by_model
79
+ end
77
80
  end
78
81
 
79
82
  # Return the list of indexes by model that exist in the database but aren't
@@ -40,7 +40,7 @@ module Mongoid
40
40
  EXECUTE_CALLBACKS = '[mongoid]:execute-callbacks'
41
41
 
42
42
  # The key for the time left in the current in-memory regexp budget.
43
- REGEXP_BUDGET_KEY = 'regexp-budget'
43
+ REGEXP_BUDGET_KEY = '[mongoid]:regexp-budget'
44
44
 
45
45
  extend self
46
46
 
@@ -5,5 +5,5 @@ module Mongoid
5
5
  #
6
6
  # Note that this file is automatically updated via `rake candidate:create`.
7
7
  # Manual changes to this file will be overwritten by that rake task.
8
- VERSION = '9.0.12'
8
+ VERSION = '9.0.13'
9
9
  end
@@ -37,5 +37,9 @@ module Mongoid
37
37
  warning :autosave_saves_unchanged_documents, "Autosave associations are currently configured to save documents even if they haven't changed. " \
38
38
  'This legacy behavior is deprecated. Set Mongoid.autosave_saves_unchanged_documents to false to ' \
39
39
  'skip saving unchanged documents in autosave associations.'
40
+ warning :bypass_auto_encryption,
41
+ 'auto_encryption_options includes bypass_auto_encryption: true. The driver ' \
42
+ 'will not encrypt anything for this client: fields declared with encrypt: true ' \
43
+ 'are written to the database unencrypted.'
40
44
  end
41
45
  end