mongo 2.11.4 → 2.12.3

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.
Files changed (357) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/CONTRIBUTING.md +1 -1
  5. data/README.md +2 -1
  6. data/lib/mongo.rb +3 -0
  7. data/lib/mongo/address.rb +44 -19
  8. data/lib/mongo/auth.rb +1 -0
  9. data/lib/mongo/auth/credential_cache.rb +51 -0
  10. data/lib/mongo/auth/scram/conversation.rb +20 -16
  11. data/lib/mongo/auth/user.rb +0 -8
  12. data/lib/mongo/auth/user/view.rb +4 -4
  13. data/lib/mongo/background_thread.rb +1 -1
  14. data/lib/mongo/bulk_write.rb +5 -5
  15. data/lib/mongo/client.rb +143 -14
  16. data/lib/mongo/client_encryption.rb +103 -0
  17. data/lib/mongo/cluster.rb +8 -4
  18. data/lib/mongo/cluster/reapers/cursor_reaper.rb +18 -6
  19. data/lib/mongo/cluster/sdam_flow.rb +54 -58
  20. data/lib/mongo/collection.rb +3 -3
  21. data/lib/mongo/collection/view.rb +1 -1
  22. data/lib/mongo/collection/view/aggregation.rb +1 -1
  23. data/lib/mongo/collection/view/change_stream.rb +12 -3
  24. data/lib/mongo/collection/view/iterable.rb +14 -5
  25. data/lib/mongo/collection/view/map_reduce.rb +2 -2
  26. data/lib/mongo/collection/view/readable.rb +9 -7
  27. data/lib/mongo/collection/view/writable.rb +7 -7
  28. data/lib/mongo/crypt.rb +33 -0
  29. data/lib/mongo/crypt/auto_decryption_context.rb +40 -0
  30. data/lib/mongo/crypt/auto_encrypter.rb +179 -0
  31. data/lib/mongo/crypt/auto_encryption_context.rb +44 -0
  32. data/lib/mongo/crypt/binary.rb +155 -0
  33. data/lib/mongo/crypt/binding.rb +1229 -0
  34. data/lib/mongo/crypt/context.rb +135 -0
  35. data/lib/mongo/crypt/data_key_context.rb +162 -0
  36. data/lib/mongo/crypt/encryption_io.rb +289 -0
  37. data/lib/mongo/crypt/explicit_decryption_context.rb +40 -0
  38. data/lib/mongo/crypt/explicit_encrypter.rb +117 -0
  39. data/lib/mongo/crypt/explicit_encryption_context.rb +89 -0
  40. data/lib/mongo/crypt/handle.rb +315 -0
  41. data/lib/mongo/crypt/hooks.rb +90 -0
  42. data/lib/mongo/crypt/kms_context.rb +67 -0
  43. data/lib/mongo/crypt/status.rb +131 -0
  44. data/lib/mongo/cursor.rb +64 -32
  45. data/lib/mongo/database.rb +23 -6
  46. data/lib/mongo/database/view.rb +13 -4
  47. data/lib/mongo/dbref.rb +9 -2
  48. data/lib/mongo/error.rb +5 -1
  49. data/lib/mongo/error/bulk_write_error.rb +16 -14
  50. data/lib/mongo/error/crypt_error.rb +31 -0
  51. data/lib/mongo/error/{failed_stringprep_validation.rb → failed_string_prep_validation.rb} +0 -0
  52. data/lib/mongo/error/invalid_cursor_operation.rb +27 -0
  53. data/lib/mongo/error/kms_error.rb +22 -0
  54. data/lib/mongo/error/max_bson_size.rb +14 -3
  55. data/lib/mongo/error/mongocryptd_spawn_error.rb +22 -0
  56. data/lib/mongo/error/no_server_available.rb +8 -3
  57. data/lib/mongo/error/notable.rb +0 -15
  58. data/lib/mongo/error/operation_failure.rb +1 -0
  59. data/lib/mongo/error/parser.rb +1 -1
  60. data/lib/mongo/grid/file.rb +5 -0
  61. data/lib/mongo/grid/file/chunk.rb +2 -0
  62. data/lib/mongo/grid/file/info.rb +3 -2
  63. data/lib/mongo/grid/fs_bucket.rb +15 -13
  64. data/lib/mongo/grid/stream/write.rb +9 -3
  65. data/lib/mongo/index/view.rb +3 -3
  66. data/lib/mongo/monitoring/event/cmap/connection_check_out_failed.rb +1 -1
  67. data/lib/mongo/monitoring/event/command_started.rb +6 -1
  68. data/lib/mongo/operation/collections_info.rb +6 -3
  69. data/lib/mongo/operation/delete/op_msg.rb +1 -1
  70. data/lib/mongo/operation/find/op_msg.rb +4 -1
  71. data/lib/mongo/operation/get_more/op_msg.rb +4 -1
  72. data/lib/mongo/operation/insert/command.rb +3 -2
  73. data/lib/mongo/operation/insert/legacy.rb +3 -2
  74. data/lib/mongo/operation/insert/op_msg.rb +3 -3
  75. data/lib/mongo/operation/result.rb +36 -27
  76. data/lib/mongo/operation/shared/executable.rb +11 -9
  77. data/lib/mongo/operation/shared/executable_no_validate.rb +2 -2
  78. data/lib/mongo/operation/shared/op_msg_or_command.rb +2 -2
  79. data/lib/mongo/operation/shared/op_msg_or_find_command.rb +2 -2
  80. data/lib/mongo/operation/shared/op_msg_or_list_indexes_command.rb +2 -2
  81. data/lib/mongo/operation/shared/read_preference_supported.rb +68 -19
  82. data/lib/mongo/operation/shared/response_handling.rb +1 -1
  83. data/lib/mongo/operation/shared/sessions_supported.rb +44 -3
  84. data/lib/mongo/operation/shared/write.rb +17 -10
  85. data/lib/mongo/operation/update/op_msg.rb +1 -1
  86. data/lib/mongo/protocol/bit_vector.rb +2 -1
  87. data/lib/mongo/protocol/compressed.rb +6 -5
  88. data/lib/mongo/protocol/insert.rb +3 -1
  89. data/lib/mongo/protocol/message.rb +94 -15
  90. data/lib/mongo/protocol/msg.rb +207 -37
  91. data/lib/mongo/protocol/query.rb +7 -9
  92. data/lib/mongo/protocol/serializers.rb +43 -15
  93. data/lib/mongo/retryable.rb +1 -1
  94. data/lib/mongo/server.rb +10 -4
  95. data/lib/mongo/server/connection.rb +20 -9
  96. data/lib/mongo/server/connection_base.rb +118 -18
  97. data/lib/mongo/server/connection_common.rb +61 -0
  98. data/lib/mongo/server/connection_pool.rb +37 -1
  99. data/lib/mongo/server/connection_pool/populator.rb +1 -1
  100. data/lib/mongo/server/description.rb +9 -11
  101. data/lib/mongo/server/monitor.rb +2 -0
  102. data/lib/mongo/server/monitor/connection.rb +3 -18
  103. data/lib/mongo/server/pending_connection.rb +2 -1
  104. data/lib/mongo/session.rb +3 -3
  105. data/lib/mongo/session/session_pool.rb +8 -3
  106. data/lib/mongo/socket.rb +29 -16
  107. data/lib/mongo/socket/ssl.rb +23 -8
  108. data/lib/mongo/socket/tcp.rb +12 -3
  109. data/lib/mongo/srv/monitor.rb +73 -42
  110. data/lib/mongo/srv/result.rb +0 -1
  111. data/lib/mongo/timeout.rb +49 -0
  112. data/lib/mongo/uri.rb +30 -1
  113. data/lib/mongo/uri/srv_protocol.rb +1 -1
  114. data/lib/mongo/version.rb +1 -1
  115. data/mongo.gemspec +1 -3
  116. data/spec/README.md +228 -7
  117. data/spec/integration/auth_spec.rb +53 -0
  118. data/spec/integration/bulk_write_spec.rb +19 -0
  119. data/spec/integration/{client_options_spec.rb → client_authentication_options_spec.rb} +10 -10
  120. data/spec/integration/client_construction_spec.rb +100 -1
  121. data/spec/integration/client_side_encryption/auto_encryption_bulk_writes_spec.rb +353 -0
  122. data/spec/integration/client_side_encryption/auto_encryption_command_monitoring_spec.rb +303 -0
  123. data/spec/integration/client_side_encryption/auto_encryption_mongocryptd_spawn_spec.rb +72 -0
  124. data/spec/integration/client_side_encryption/auto_encryption_old_wire_version_spec.rb +79 -0
  125. data/spec/integration/client_side_encryption/auto_encryption_reconnect_spec.rb +221 -0
  126. data/spec/integration/client_side_encryption/auto_encryption_spec.rb +601 -0
  127. data/spec/integration/client_side_encryption/bson_size_limit_spec.rb +187 -0
  128. data/spec/integration/client_side_encryption/bypass_mongocryptd_spawn_spec.rb +78 -0
  129. data/spec/integration/client_side_encryption/client_close_spec.rb +63 -0
  130. data/spec/integration/client_side_encryption/corpus_spec.rb +233 -0
  131. data/spec/integration/client_side_encryption/custom_endpoint_spec.rb +132 -0
  132. data/spec/integration/client_side_encryption/data_key_spec.rb +165 -0
  133. data/spec/integration/client_side_encryption/explicit_encryption_spec.rb +114 -0
  134. data/spec/integration/client_side_encryption/external_key_vault_spec.rb +141 -0
  135. data/spec/integration/client_side_encryption/views_spec.rb +44 -0
  136. data/spec/integration/client_update_spec.rb +154 -0
  137. data/spec/integration/command_monitoring_spec.rb +3 -1
  138. data/spec/integration/command_spec.rb +44 -10
  139. data/spec/integration/connection_spec.rb +57 -0
  140. data/spec/integration/crud_spec.rb +89 -0
  141. data/spec/integration/grid_fs_bucket_spec.rb +48 -0
  142. data/spec/integration/read_preference_spec.rb +26 -0
  143. data/spec/integration/reconnect_spec.rb +7 -6
  144. data/spec/integration/size_limit_spec.rb +111 -0
  145. data/spec/integration/srv_monitoring_spec.rb +16 -8
  146. data/spec/integration/zlib_compression_spec.rb +25 -0
  147. data/spec/kerberos/kerberos_spec.rb +87 -0
  148. data/spec/lite_spec_helper.rb +34 -29
  149. data/spec/mongo/auth/cr_spec.rb +8 -0
  150. data/spec/mongo/auth/ldap_spec.rb +5 -1
  151. data/spec/mongo/auth/scram/conversation_spec.rb +5 -6
  152. data/spec/mongo/auth/scram/negotiation_spec.rb +74 -75
  153. data/spec/mongo/auth/scram_spec.rb +45 -35
  154. data/spec/mongo/auth/user/view_spec.rb +3 -6
  155. data/spec/mongo/auth/x509_spec.rb +5 -1
  156. data/spec/mongo/bulk_write/result_spec.rb +11 -7
  157. data/spec/mongo/client_construction_spec.rb +206 -2
  158. data/spec/mongo/client_encryption_spec.rb +405 -0
  159. data/spec/mongo/cluster/cursor_reaper_spec.rb +12 -8
  160. data/spec/mongo/cluster/socket_reaper_spec.rb +14 -3
  161. data/spec/mongo/collection/view/aggregation_spec.rb +0 -2
  162. data/spec/mongo/collection/view/change_stream_spec.rb +7 -7
  163. data/spec/mongo/collection/view/map_reduce_spec.rb +3 -3
  164. data/spec/mongo/collection/view_spec.rb +1 -1
  165. data/spec/mongo/collection_spec.rb +28 -9
  166. data/spec/mongo/crypt/auto_decryption_context_spec.rb +90 -0
  167. data/spec/mongo/crypt/auto_encrypter_spec.rb +187 -0
  168. data/spec/mongo/crypt/auto_encryption_context_spec.rb +107 -0
  169. data/spec/mongo/crypt/binary_spec.rb +115 -0
  170. data/spec/mongo/crypt/binding/binary_spec.rb +56 -0
  171. data/spec/mongo/crypt/binding/context_spec.rb +257 -0
  172. data/spec/mongo/crypt/binding/helpers_spec.rb +46 -0
  173. data/spec/mongo/crypt/binding/mongocrypt_spec.rb +144 -0
  174. data/spec/mongo/crypt/binding/status_spec.rb +99 -0
  175. data/spec/mongo/crypt/binding/version_spec.rb +22 -0
  176. data/spec/mongo/crypt/binding_unloaded_spec.rb +20 -0
  177. data/spec/mongo/crypt/data_key_context_spec.rb +213 -0
  178. data/spec/mongo/crypt/encryption_io_spec.rb +136 -0
  179. data/spec/mongo/crypt/explicit_decryption_context_spec.rb +72 -0
  180. data/spec/mongo/crypt/explicit_encryption_context_spec.rb +170 -0
  181. data/spec/mongo/crypt/handle_spec.rb +232 -0
  182. data/spec/mongo/crypt/helpers/mongo_crypt_spec_helper.rb +108 -0
  183. data/spec/mongo/crypt/status_spec.rb +152 -0
  184. data/spec/mongo/cursor_spec.rb +24 -4
  185. data/spec/mongo/database_spec.rb +20 -0
  186. data/spec/mongo/error/bulk_write_error_spec.rb +49 -0
  187. data/spec/mongo/error/crypt_error_spec.rb +26 -0
  188. data/spec/mongo/error/max_bson_size_spec.rb +35 -0
  189. data/spec/mongo/error/no_server_available_spec.rb +11 -1
  190. data/spec/mongo/error/notable_spec.rb +59 -0
  191. data/spec/mongo/error/operation_failure_spec.rb +6 -6
  192. data/spec/mongo/operation/aggregate_spec.rb +1 -1
  193. data/spec/mongo/operation/collections_info_spec.rb +1 -1
  194. data/spec/mongo/operation/command_spec.rb +3 -3
  195. data/spec/mongo/operation/create_index_spec.rb +3 -3
  196. data/spec/mongo/operation/create_user_spec.rb +3 -3
  197. data/spec/mongo/operation/delete/bulk_spec.rb +6 -6
  198. data/spec/mongo/operation/delete/op_msg_spec.rb +1 -6
  199. data/spec/mongo/operation/delete_spec.rb +7 -7
  200. data/spec/mongo/operation/drop_index_spec.rb +2 -2
  201. data/spec/mongo/operation/find/legacy_spec.rb +2 -1
  202. data/spec/mongo/operation/get_more_spec.rb +1 -1
  203. data/spec/mongo/operation/indexes_spec.rb +1 -1
  204. data/spec/mongo/operation/insert/bulk_spec.rb +7 -7
  205. data/spec/mongo/operation/insert/op_msg_spec.rb +3 -6
  206. data/spec/mongo/operation/insert_spec.rb +12 -12
  207. data/spec/mongo/operation/map_reduce_spec.rb +2 -2
  208. data/spec/mongo/operation/read_preference_legacy_spec.rb +351 -0
  209. data/spec/mongo/operation/read_preference_op_msg_spec.rb +194 -0
  210. data/spec/mongo/operation/remove_user_spec.rb +3 -3
  211. data/spec/mongo/operation/update/bulk_spec.rb +6 -6
  212. data/spec/mongo/operation/update/op_msg_spec.rb +3 -6
  213. data/spec/mongo/operation/update_spec.rb +7 -7
  214. data/spec/mongo/operation/update_user_spec.rb +1 -1
  215. data/spec/mongo/protocol/compressed_spec.rb +2 -3
  216. data/spec/mongo/protocol/delete_spec.rb +9 -8
  217. data/spec/mongo/protocol/get_more_spec.rb +9 -8
  218. data/spec/mongo/protocol/insert_spec.rb +9 -8
  219. data/spec/mongo/protocol/kill_cursors_spec.rb +6 -5
  220. data/spec/mongo/protocol/msg_spec.rb +57 -53
  221. data/spec/mongo/protocol/query_spec.rb +12 -12
  222. data/spec/mongo/protocol/registry_spec.rb +1 -1
  223. data/spec/mongo/protocol/reply_spec.rb +1 -1
  224. data/spec/mongo/protocol/update_spec.rb +10 -9
  225. data/spec/mongo/server/connection_pool_spec.rb +1 -1
  226. data/spec/mongo/server/connection_spec.rb +28 -7
  227. data/spec/mongo/socket_spec.rb +1 -1
  228. data/spec/mongo/srv/monitor_spec.rb +88 -69
  229. data/spec/mongo/timeout_spec.rb +85 -0
  230. data/spec/mongo/uri/srv_protocol_spec.rb +2 -2
  231. data/spec/mongo/uri_spec.rb +52 -5
  232. data/spec/mongo/write_concern_spec.rb +13 -1
  233. data/spec/{support → runners}/auth.rb +14 -1
  234. data/spec/{support → runners}/change_streams.rb +1 -1
  235. data/spec/{support → runners}/change_streams/operation.rb +0 -0
  236. data/spec/{support → runners}/cmap.rb +1 -1
  237. data/spec/{support → runners}/cmap/verifier.rb +0 -0
  238. data/spec/{support → runners}/command_monitoring.rb +0 -0
  239. data/spec/runners/connection_string.rb +358 -4
  240. data/spec/{support → runners}/crud.rb +9 -9
  241. data/spec/{support → runners}/crud/context.rb +0 -0
  242. data/spec/{support → runners}/crud/operation.rb +7 -3
  243. data/spec/{support → runners}/crud/outcome.rb +0 -0
  244. data/spec/{support → runners}/crud/requirement.rb +1 -1
  245. data/spec/{support → runners}/crud/spec.rb +12 -1
  246. data/spec/{support → runners}/crud/test.rb +0 -0
  247. data/spec/{support → runners}/crud/test_base.rb +0 -0
  248. data/spec/{support → runners}/crud/verifier.rb +10 -12
  249. data/spec/{support → runners}/gridfs.rb +0 -0
  250. data/spec/{support → runners}/sdam_monitoring.rb +0 -0
  251. data/spec/{support → runners}/server_discovery_and_monitoring.rb +0 -0
  252. data/spec/{support → runners}/server_selection.rb +0 -0
  253. data/spec/{support → runners}/server_selection_rtt.rb +0 -0
  254. data/spec/{support → runners}/transactions.rb +9 -11
  255. data/spec/{support → runners}/transactions/context.rb +0 -0
  256. data/spec/{support → runners}/transactions/operation.rb +0 -0
  257. data/spec/{support → runners}/transactions/spec.rb +0 -0
  258. data/spec/{support → runners}/transactions/test.rb +37 -5
  259. data/spec/spec_helper.rb +0 -5
  260. data/spec/spec_tests/auth_spec.rb +3 -3
  261. data/spec/spec_tests/client_side_encryption_spec.rb +8 -0
  262. data/spec/spec_tests/connection_string_spec.rb +1 -1
  263. data/spec/spec_tests/data/auth/connection-string.yml +13 -0
  264. data/spec/spec_tests/data/client_side_encryption/aggregate.yml +134 -0
  265. data/spec/spec_tests/data/client_side_encryption/badQueries.yml +526 -0
  266. data/spec/spec_tests/data/client_side_encryption/badSchema.yml +73 -0
  267. data/spec/spec_tests/data/client_side_encryption/basic.yml +116 -0
  268. data/spec/spec_tests/data/client_side_encryption/bulk.yml +88 -0
  269. data/spec/spec_tests/data/client_side_encryption/bypassAutoEncryption.yml +100 -0
  270. data/spec/spec_tests/data/client_side_encryption/bypassedCommand.yml +42 -0
  271. data/spec/spec_tests/data/client_side_encryption/count.yml +61 -0
  272. data/spec/spec_tests/data/client_side_encryption/countDocuments.yml +59 -0
  273. data/spec/spec_tests/data/client_side_encryption/delete.yml +105 -0
  274. data/spec/spec_tests/data/client_side_encryption/distinct.yml +73 -0
  275. data/spec/spec_tests/data/client_side_encryption/explain.yml +64 -0
  276. data/spec/spec_tests/data/client_side_encryption/find.yml +119 -0
  277. data/spec/spec_tests/data/client_side_encryption/findOneAndDelete.yml +57 -0
  278. data/spec/spec_tests/data/client_side_encryption/findOneAndReplace.yml +57 -0
  279. data/spec/spec_tests/data/client_side_encryption/findOneAndUpdate.yml +57 -0
  280. data/spec/spec_tests/data/client_side_encryption/getMore.yml +68 -0
  281. data/spec/spec_tests/data/client_side_encryption/insert.yml +102 -0
  282. data/spec/spec_tests/data/client_side_encryption/keyAltName.yml +71 -0
  283. data/spec/spec_tests/data/client_side_encryption/localKMS.yml +54 -0
  284. data/spec/spec_tests/data/client_side_encryption/localSchema.yml +72 -0
  285. data/spec/spec_tests/data/client_side_encryption/malformedCiphertext.yml +69 -0
  286. data/spec/spec_tests/data/client_side_encryption/maxWireVersion.yml +20 -0
  287. data/spec/spec_tests/data/client_side_encryption/missingKey.yml +49 -0
  288. data/spec/spec_tests/data/client_side_encryption/replaceOne.yml +64 -0
  289. data/spec/spec_tests/data/client_side_encryption/types.yml +527 -0
  290. data/spec/spec_tests/data/client_side_encryption/unsupportedCommand.yml +25 -0
  291. data/spec/spec_tests/data/client_side_encryption/updateMany.yml +77 -0
  292. data/spec/spec_tests/data/client_side_encryption/updateOne.yml +171 -0
  293. data/spec/spec_tests/data/read_write_concern/connection-string/write-concern.yml +1 -4
  294. data/spec/spec_tests/data/retryable_writes/insertOne-serverErrors.yml +21 -0
  295. data/spec/spec_tests/data/sdam/rs/incompatible_ghost.yml +2 -4
  296. data/spec/spec_tests/data/sdam/rs/incompatible_other.yml +1 -1
  297. data/spec/spec_tests/data/sdam/rs/primary_mismatched_me_not_removed.yml +73 -0
  298. data/spec/spec_tests/data/sdam/rs/primary_to_no_primary_mismatched_me.yml +1 -2
  299. data/spec/spec_tests/data/sdam/rs/repeated.yml +101 -0
  300. data/spec/spec_tests/data/sdam/rs/{primary_address_change.yml → ruby_primary_address_change.yml} +2 -0
  301. data/spec/spec_tests/data/sdam/rs/{secondary_wrong_set_name_with_primary_second.yml → ruby_secondary_wrong_set_name_with_primary_second.yml} +0 -0
  302. data/spec/spec_tests/data/sdam/sharded/ruby_discovered_single_mongos.yml +27 -0
  303. data/spec/spec_tests/data/sdam/sharded/{primary_address_change.yml → ruby_primary_different_address.yml} +1 -1
  304. data/spec/spec_tests/data/sdam/sharded/{primary_mismatched_me.yml → ruby_primary_mismatched_me.yml} +1 -1
  305. data/spec/spec_tests/data/sdam/single/{primary_address_change.yml → ruby_primary_different_address.yml} +1 -1
  306. data/spec/spec_tests/data/sdam/single/{primary_mismatched_me.yml → ruby_primary_mismatched_me.yml} +1 -1
  307. data/spec/spec_tests/data/sdam_monitoring/{replica_set_with_primary_change.yml → replica_set_primary_address_change.yml} +27 -5
  308. data/spec/spec_tests/data/sdam_monitoring/replica_set_with_me_mismatch.yml +26 -74
  309. data/spec/spec_tests/data/sdam_monitoring/replica_set_with_removal.yml +20 -16
  310. data/spec/spec_tests/data/sdam_monitoring/standalone_suppress_equal_description_changes.yml +73 -0
  311. data/spec/spec_tests/data/transactions/pin-mongos.yml +2 -3
  312. data/spec/spec_tests/data/uri_options/auth-options.yml +10 -0
  313. data/spec/spec_tests/data/uri_options/tls-options.yml +75 -4
  314. data/spec/spec_tests/read_write_concern_connection_string_spec.rb +1 -1
  315. data/spec/spec_tests/uri_options_spec.rb +6 -8
  316. data/spec/stress/connection_pool_timing_spec.rb +6 -3
  317. data/spec/support/certificates/README.md +4 -0
  318. data/spec/support/certificates/server-second-level-bundle.pem +77 -77
  319. data/spec/support/certificates/server-second-level.crt +52 -52
  320. data/spec/support/certificates/server-second-level.key +25 -25
  321. data/spec/support/certificates/server-second-level.pem +77 -77
  322. data/spec/support/client_registry.rb +19 -3
  323. data/spec/support/cluster_config.rb +9 -1
  324. data/spec/support/cluster_tools.rb +6 -1
  325. data/spec/support/common_shortcuts.rb +12 -0
  326. data/spec/support/constraints.rb +16 -0
  327. data/spec/support/crypt.rb +154 -0
  328. data/spec/support/crypt/corpus/corpus-key-aws.json +33 -0
  329. data/spec/support/crypt/corpus/corpus-key-local.json +31 -0
  330. data/spec/support/crypt/corpus/corpus-schema.json +2057 -0
  331. data/spec/support/crypt/corpus/corpus.json +3657 -0
  332. data/spec/support/crypt/corpus/corpus_encrypted.json +4152 -0
  333. data/spec/support/crypt/data_keys/key_document_aws.json +34 -0
  334. data/spec/support/crypt/data_keys/key_document_local.json +31 -0
  335. data/spec/support/crypt/external/external-key.json +31 -0
  336. data/spec/support/crypt/external/external-schema.json +19 -0
  337. data/spec/support/crypt/limits/limits-doc.json +102 -0
  338. data/spec/support/crypt/limits/limits-key.json +31 -0
  339. data/spec/support/crypt/limits/limits-schema.json +1405 -0
  340. data/spec/support/crypt/schema_maps/schema_map_aws.json +17 -0
  341. data/spec/support/crypt/schema_maps/schema_map_aws_key_alt_names.json +12 -0
  342. data/spec/support/crypt/schema_maps/schema_map_local.json +18 -0
  343. data/spec/support/crypt/schema_maps/schema_map_local_key_alt_names.json +12 -0
  344. data/spec/support/lite_constraints.rb +19 -1
  345. data/spec/support/matchers.rb +19 -0
  346. data/spec/support/shared/protocol.rb +2 -0
  347. data/spec/support/spec_config.rb +53 -13
  348. data/spec/support/utils.rb +140 -10
  349. metadata +894 -687
  350. metadata.gz.sig +0 -0
  351. data/lib/mongo/cluster/srv_monitor.rb +0 -127
  352. data/lib/mongo/srv/warning_result.rb +0 -35
  353. data/spec/enterprise_auth/kerberos_spec.rb +0 -58
  354. data/spec/mongo/cluster/srv_monitor_spec.rb +0 -214
  355. data/spec/mongo/operation/read_preference_spec.rb +0 -245
  356. data/spec/spec_tests/data/sdam/sharded/single_mongos.yml +0 -33
  357. data/spec/support/connection_string.rb +0 -354
@@ -0,0 +1,187 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Client-Side Encryption' do
4
+ describe 'Prose tests: BSON size limits and batch splitting' do
5
+ require_libmongocrypt
6
+ require_enterprise
7
+ min_server_fcv '4.2'
8
+
9
+ include_context 'define shared FLE helpers'
10
+
11
+ let(:subscriber) { EventSubscriber.new }
12
+
13
+ let(:client) do
14
+ authorized_client.use('db')
15
+ end
16
+
17
+ let(:json_schema) do
18
+ BSON::ExtJSON.parse(File.read('spec/support/crypt/limits/limits-schema.json'))
19
+ end
20
+
21
+ let(:limits_doc) do
22
+ BSON::ExtJSON.parse(File.read('spec/support/crypt/limits/limits-doc.json'))
23
+ end
24
+
25
+ let(:client_encrypted) do
26
+ new_local_client(
27
+ SpecConfig.instance.addresses,
28
+ SpecConfig.instance.test_options.merge(
29
+ auto_encryption_options: {
30
+ kms_providers: {
31
+ local: { key: local_master_key },
32
+ },
33
+ key_vault_namespace: 'admin.datakeys',
34
+ # Spawn mongocryptd on non-default port for sharded cluster tests
35
+ extra_options: extra_options,
36
+ },
37
+ database: 'db',
38
+ )
39
+ ).tap do |client|
40
+ client.subscribe(Mongo::Monitoring::COMMAND, subscriber)
41
+ end
42
+ end
43
+
44
+ before do
45
+ client['coll'].drop
46
+ client['coll',
47
+ {
48
+ 'validator' => { '$jsonSchema' => json_schema }
49
+ }
50
+ ].create
51
+
52
+ key_vault_collection = client.use('admin')['datakeys', write_concern: { w: :majority }]
53
+
54
+ key_vault_collection.drop
55
+ key_vault_collection.insert_one(
56
+ BSON::ExtJSON.parse(File.read('spec/support/crypt/limits/limits-key.json'))
57
+ )
58
+ end
59
+
60
+ let(:_2mib) { 2097152 }
61
+ let(:_16mib) { 16777216 }
62
+
63
+ context 'when a single, unencrypted document is larger than 2MiB' do
64
+ it 'can perform insert_one using the encrypted client' do
65
+ document = {
66
+ _id: "over_2mib_under_16mib",
67
+ unencrypted: 'a' * _2mib
68
+ }
69
+
70
+ result = client_encrypted['coll'].insert_one(document)
71
+
72
+ expect(result).to be_ok
73
+ end
74
+ end
75
+
76
+ context 'when a single encrypted document is larger than 2MiB' do
77
+ it 'can perform insert_one using the encrypted client' do
78
+ result = client_encrypted['coll'].insert_one(
79
+ limits_doc.merge(
80
+ _id: "encryption_exceeds_2mi",
81
+ unencrypted: 'a' * (_2mib - 2000)
82
+ )
83
+ )
84
+
85
+ expect(result).to be_ok
86
+ end
87
+ end
88
+
89
+ context 'when bulk inserting two unencrypted documents under 2MiB' do
90
+ it 'can perform bulk insert using the encrypted client' do
91
+ bulk_write = Mongo::BulkWrite.new(
92
+ client_encrypted['coll'],
93
+ [
94
+ { insert_one: { _id: 'over_2mib_1', unencrypted: 'a' * _2mib } },
95
+ { insert_one: { _id: 'over_2mib_2', unencrypted: 'a' * _2mib } },
96
+ ]
97
+ )
98
+
99
+ result = bulk_write.execute
100
+ expect(result.inserted_count).to eq(2)
101
+
102
+ command_succeeded_events = subscriber.succeeded_events.select do |event|
103
+ event.command_name == 'insert'
104
+ end
105
+
106
+ expect(command_succeeded_events.length).to eq(2)
107
+ end
108
+ end
109
+
110
+ context 'when bulk deletes two unencrypted documents under 2MiB' do
111
+ it 'can perform bulk delete using the encrypted client' do
112
+ # Insert documents that we can match and delete later
113
+ bulk_write = Mongo::BulkWrite.new(
114
+ client_encrypted['coll'],
115
+ [
116
+ { insert_one: { _id: 'over_2mib_1', unencrypted: 'a' * _2mib } },
117
+ { insert_one: { _id: 'over_2mib_2', unencrypted: 'a' * _2mib } },
118
+ ]
119
+ )
120
+
121
+ result = bulk_write.execute
122
+ expect(result.inserted_count).to eq(2)
123
+
124
+ command_succeeded_events = subscriber.succeeded_events.select do |event|
125
+ event.command_name == 'insert'
126
+ end
127
+
128
+ expect(command_succeeded_events.length).to eq(2)
129
+ end
130
+ end
131
+
132
+ context 'when bulk inserting two encrypted documents under 2MiB' do
133
+ it 'can perform bulk_insert using the encrypted client' do
134
+ bulk_write = Mongo::BulkWrite.new(
135
+ client_encrypted['coll'],
136
+ [
137
+ {
138
+ insert_one: limits_doc.merge(
139
+ _id: "encryption_exceeds_2mib_1",
140
+ unencrypted: 'a' * (_2mib - 2000)
141
+ )
142
+ },
143
+ {
144
+ insert_one: limits_doc.merge(
145
+ _id: 'encryption_exceeds_2mib_2',
146
+ unencrypted: 'a' * (_2mib - 2000)
147
+ )
148
+ },
149
+ ]
150
+ )
151
+
152
+ result = bulk_write.execute
153
+ expect(result.inserted_count).to eq(2)
154
+
155
+ command_succeeded_events = subscriber.succeeded_events.select do |event|
156
+ event.command_name == 'insert'
157
+ end
158
+
159
+ expect(command_succeeded_events.length).to eq(2)
160
+ end
161
+ end
162
+
163
+ context 'when a single document is just smaller than 16MiB' do
164
+ it 'can perform insert_one using the encrypted client' do
165
+ result = client_encrypted['coll'].insert_one(
166
+ _id: "under_16mib",
167
+ unencrypted: "a" * (_16mib - 2000)
168
+ )
169
+
170
+ expect(result).to be_ok
171
+ end
172
+ end
173
+
174
+ context 'when an encrypted document is greater than the 16MiB limit' do
175
+ it 'raises an exception when attempting to insert the document' do
176
+ expect do
177
+ client_encrypted['coll'].insert_one(
178
+ limits_doc.merge(
179
+ _id: "encryption_exceeds_16mib",
180
+ unencrypted: "a" * (16*1024*1024 + 500*1024),
181
+ )
182
+ )
183
+ end.to raise_error(Mongo::Error::MaxBSONSize, /The document exceeds maximum allowed BSON object size after serialization/)
184
+ end
185
+ end
186
+ end
187
+ end
@@ -0,0 +1,78 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Client-Side Encryption' do
4
+ describe 'Prose tests: Bypass mongocryptd spawn' do
5
+ require_libmongocrypt
6
+ require_enterprise
7
+ min_server_fcv '4.2'
8
+
9
+ include_context 'define shared FLE helpers'
10
+
11
+ # Choose a different port for mongocryptd than the one used by all the other
12
+ # tests to avoid failures caused by other tests spawning mongocryptd.
13
+ let(:mongocryptd_port) { 27091 }
14
+
15
+ context 'via mongocryptdBypassSpawn' do
16
+ let(:test_schema_map) do
17
+ BSON::ExtJSON.parse(File.read('spec/support/crypt/external/external-schema.json'))
18
+ end
19
+
20
+ let(:client) do
21
+ new_local_client(
22
+ SpecConfig.instance.addresses,
23
+ SpecConfig.instance.test_options.merge(
24
+ auto_encryption_options: {
25
+ kms_providers: local_kms_providers,
26
+ key_vault_namespace: 'admin.datakeys',
27
+ schema_map: { 'db.coll' => test_schema_map },
28
+ extra_options: {
29
+ mongocryptd_bypass_spawn: true,
30
+ mongocryptd_uri: "mongodb://localhost:#{mongocryptd_port}/db?serverSelectionTimeoutMS=1000",
31
+ mongocryptd_spawn_args: [ "--pidfilepath=bypass-spawning-mongocryptd.pid", "--port=#{mongocryptd_port}"],
32
+ },
33
+ },
34
+ database: 'db'
35
+ ),
36
+ )
37
+ end
38
+
39
+ it 'does not spawn' do
40
+ lambda do
41
+ client['coll'].insert_one(encrypted: 'test')
42
+ end.should raise_error(Mongo::Error::NoServerAvailable, /Server address=localhost:#{Regexp.quote(mongocryptd_port.to_s)} UNKNOWN/)
43
+ end
44
+ end
45
+
46
+ context 'via bypassAutoEncryption' do
47
+ let(:client) do
48
+ new_local_client(
49
+ SpecConfig.instance.addresses,
50
+ SpecConfig.instance.test_options.merge(
51
+ auto_encryption_options: {
52
+ kms_providers: local_kms_providers,
53
+ key_vault_namespace: 'admin.datakeys',
54
+ bypass_auto_encryption: true,
55
+ extra_options: {
56
+ mongocryptd_spawn_args: [ "--pidfilepath=bypass-spawning-mongocryptd.pid", "--port=#{mongocryptd_port}"],
57
+ },
58
+ },
59
+ database: 'db'
60
+ ),
61
+ )
62
+ end
63
+
64
+ let(:mongocryptd_client) do
65
+ new_local_client(["localhost:#{mongocryptd_port}"], server_selection_timeout: 1)
66
+ end
67
+
68
+ it 'does not spawn' do
69
+ lambda do
70
+ client['coll'].insert_one(encrypted: 'test')
71
+ end.should_not raise_error
72
+ lambda do
73
+ mongocryptd_client.database.command(ismaster: 1)
74
+ end.should raise_error(Mongo::Error::NoServerAvailable)
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,63 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Auto encryption client' do
4
+ require_libmongocrypt
5
+ require_enterprise
6
+ min_server_fcv '4.2'
7
+
8
+ context 'after client is disconnected' do
9
+ include_context 'define shared FLE helpers'
10
+ include_context 'with local kms_providers'
11
+
12
+ let(:client) do
13
+ new_local_client(
14
+ SpecConfig.instance.addresses,
15
+ SpecConfig.instance.test_options.merge(
16
+ auto_encryption_options: {
17
+ kms_providers: kms_providers,
18
+ key_vault_namespace: 'admin.datakeys',
19
+ schema_map: { 'auto_encryption.users' => schema_map },
20
+ # Spawn mongocryptd on non-default port for sharded cluster tests
21
+ extra_options: extra_options,
22
+ },
23
+ database: 'auto_encryption',
24
+ )
25
+ )
26
+ end
27
+
28
+ shared_examples 'a functioning auto-encrypter' do
29
+ it 'can still perform encryption' do
30
+ result = client['users'].insert_one(ssn: '000-000-0000')
31
+ expect(result).to be_ok
32
+
33
+ encrypted_document = authorized_client
34
+ .use('auto_encryption')['users']
35
+ .find(_id: result.inserted_ids.first)
36
+ .first
37
+
38
+ expect(encrypted_document['ssn']).to be_ciphertext
39
+ end
40
+ end
41
+
42
+ context 'after performing operation with auto encryption' do
43
+ before do
44
+ key_vault_collection.drop
45
+ key_vault_collection.insert_one(data_key)
46
+
47
+ client['users'].insert_one(ssn: ssn)
48
+ client.close
49
+ end
50
+
51
+ it_behaves_like 'a functioning auto-encrypter'
52
+ end
53
+
54
+ context 'after performing operation without auto encryption' do
55
+ before do
56
+ client['users'].insert_one(age: 23)
57
+ client.close
58
+ end
59
+
60
+ it_behaves_like 'a functioning auto-encrypter'
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,233 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Client-Side Encryption' do
4
+ describe 'Prose tests: Corpus Test' do
5
+ require_libmongocrypt
6
+ require_enterprise
7
+ min_server_fcv '4.2'
8
+
9
+ include_context 'define shared FLE helpers'
10
+
11
+ let(:client) { authorized_client }
12
+
13
+ let(:key_vault_client) do
14
+ client.with(
15
+ database: 'admin',
16
+ write_concern: { w: :majority }
17
+ )['datakeys']
18
+ end
19
+
20
+ let(:test_schema_map) { BSON::ExtJSON.parse(File.read('spec/support/crypt/corpus/corpus-schema.json')) }
21
+ let(:local_data_key) { BSON::ExtJSON.parse(File.read('spec/support/crypt/corpus/corpus-key-local.json')) }
22
+ let(:aws_data_key) { BSON::ExtJSON.parse(File.read('spec/support/crypt/corpus/corpus-key-aws.json')) }
23
+
24
+ let(:client_encrypted) do
25
+ new_local_client(
26
+ SpecConfig.instance.addresses,
27
+ SpecConfig.instance.test_options.merge(
28
+ auto_encryption_options: {
29
+ kms_providers: {
30
+ local: { key: local_master_key },
31
+ aws: {
32
+ access_key_id: SpecConfig.instance.fle_aws_key,
33
+ secret_access_key: SpecConfig.instance.fle_aws_secret,
34
+ },
35
+ },
36
+ key_vault_namespace: 'admin.datakeys',
37
+ schema_map: local_schema_map,
38
+ # Spawn mongocryptd on non-default port for sharded cluster tests
39
+ extra_options: extra_options,
40
+ },
41
+ database: 'db',
42
+ )
43
+ )
44
+ end
45
+
46
+ let(:client_encryption) do
47
+ Mongo::ClientEncryption.new(
48
+ client,
49
+ {
50
+ kms_providers: {
51
+ local: { key: local_master_key },
52
+ aws: {
53
+ access_key_id: SpecConfig.instance.fle_aws_key,
54
+ secret_access_key: SpecConfig.instance.fle_aws_secret,
55
+ }
56
+ },
57
+ key_vault_namespace: 'admin.datakeys',
58
+ },
59
+ )
60
+ end
61
+
62
+ let(:corpus) do
63
+ BSON::ExtJSON.parse(File.read('spec/support/crypt/corpus/corpus.json'), mode: :bson)
64
+ end
65
+
66
+ let(:corpus_encrypted_expected) do
67
+ BSON::ExtJSON.parse(File.read('spec/support/crypt/corpus/corpus_encrypted.json'))
68
+ end
69
+
70
+ let(:corpus_copied) do
71
+ # As per the instructions of the prose spec, corpus_copied is a copy of
72
+ # the corpus BSON::Document that encrypts all fields that are meant to
73
+ # be explicitly encrypted. corpus is a document containing many
74
+ # sub-documents, each with a value to encrypt and information about how
75
+ # to encrypt that value.
76
+ corpus_copied = BSON::Document.new
77
+ corpus.each do |key, doc|
78
+ if ['_id', 'altname_aws', 'altname_local'].include?(key)
79
+ corpus_copied[key] = doc
80
+ next
81
+ end
82
+
83
+ if doc['method'] == 'auto'
84
+ corpus_copied[key] = doc
85
+ elsif doc['method'] == 'explicit'
86
+ options = if doc['identifier'] == 'id'
87
+ key_id = if doc['kms'] == 'local'
88
+ 'LOCALAAAAAAAAAAAAAAAAA=='
89
+ else
90
+ 'AWSAAAAAAAAAAAAAAAAAAA=='
91
+ end
92
+
93
+ { key_id: BSON::Binary.new(Base64.decode64(key_id), :uuid) }
94
+ elsif doc['identifier'] == 'altname'
95
+ { key_alt_name: doc['kms'] }
96
+ end
97
+
98
+ algorithm = if doc['algo'] == 'rand'
99
+ 'AEAD_AES_256_CBC_HMAC_SHA_512-Random'
100
+ else
101
+ 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'
102
+ end
103
+
104
+ begin
105
+ encrypted_value = client_encryption.encrypt(
106
+ doc['value'],
107
+ options.merge({ algorithm: algorithm })
108
+ )
109
+
110
+ corpus_copied[key] = doc.merge('value' => encrypted_value)
111
+ rescue => e
112
+ # If doc['allowed'] is true, it means that this field should have
113
+ # been encrypted without error, and thus that this error is unexpected.
114
+ # If doc['allowed'] is false, this error was expected and the value
115
+ # should be copied over without being encrypted.
116
+ if doc['allowed']
117
+ raise "Unexpected error occured in client-side encryption " +
118
+ "corpus tests: #{e.class}: #{e.message}"
119
+ end
120
+
121
+ corpus_copied[key] = doc
122
+ end
123
+ end
124
+ end
125
+
126
+ corpus_copied
127
+ end
128
+
129
+ before do
130
+ client.use('db')['coll'].drop
131
+
132
+ key_vault_collection = client.use('admin')['datakeys', write_concern: { w: :majority }]
133
+ key_vault_collection.drop
134
+ key_vault_collection.insert_one(local_data_key)
135
+ key_vault_collection.insert_one(aws_data_key)
136
+ end
137
+
138
+ shared_context 'with jsonSchema collection validator' do
139
+ let(:local_schema_map) { nil }
140
+
141
+ before do
142
+ client.use('db')['coll',
143
+ {
144
+ 'validator' => { '$jsonSchema' => test_schema_map }
145
+ }
146
+ ].create
147
+ end
148
+ end
149
+
150
+ shared_context 'with local schema map' do
151
+ let(:local_schema_map) { { 'db.coll' => test_schema_map } }
152
+ end
153
+
154
+ shared_examples 'a functioning encrypter' do
155
+ it 'properly encrypts and decrypts a document' do
156
+ corpus_encrypted_id = client_encrypted['coll']
157
+ .insert_one(corpus_copied)
158
+ .inserted_id
159
+
160
+ corpus_decrypted = client_encrypted['coll']
161
+ .find(_id: corpus_encrypted_id)
162
+ .first
163
+
164
+ # Ensure that corpus_decrypted is the same as the original corpus
165
+ # document by checking that they have the same set of keys, and that
166
+ # they have the same values at those keys (improved diagnostics).
167
+ expect(corpus_decrypted.keys).to eq(corpus.keys)
168
+
169
+ corpus_decrypted.each do |key, doc|
170
+ expect(key => doc).to eq(key => corpus[key])
171
+ end
172
+
173
+ corpus_encrypted_actual = client
174
+ .use('db')['coll']
175
+ .find(_id: corpus_encrypted_id)
176
+ .first
177
+
178
+ # Check that the actual encrypted document matches the expected
179
+ # encrypted document.
180
+ expect(corpus_encrypted_actual.keys).to eq(corpus_encrypted_expected.keys)
181
+
182
+ corpus_encrypted_actual.each do |key, value|
183
+ # If it was deterministically encrypted, test the encrypted values
184
+ # for equality.
185
+ if value['algo'] == 'det'
186
+ expect(value['value']).to eq(corpus_encrypted_expected[key]['value'])
187
+ else
188
+ # If the document was randomly encrypted, the two encrypted values
189
+ # will not be equal. Ensure that they are equal when decrypted.
190
+ if value['allowed']
191
+ actual_decrypted_value = client_encryption.decrypt(value['value'])
192
+ expected_decrypted_value = client_encryption.decrypt(corpus_encrypted_expected[key]['value'])
193
+
194
+ expect(actual_decrypted_value).to eq(expected_decrypted_value)
195
+ else
196
+ # If 'allowed' was false, the value was never encrypted; ensure
197
+ # that it is equal to the original, unencrypted value.
198
+ expect(value['value']).to eq(corpus[key]['value'])
199
+ end
200
+ end
201
+ end
202
+ end
203
+ end
204
+
205
+ context 'with local KMS provider' do
206
+ include_context 'with local kms_providers'
207
+
208
+ context 'with collection validator' do
209
+ include_context 'with jsonSchema collection validator'
210
+ it_behaves_like 'a functioning encrypter'
211
+ end
212
+
213
+ context 'with schema map' do
214
+ include_context 'with local schema map'
215
+ it_behaves_like 'a functioning encrypter'
216
+ end
217
+ end
218
+
219
+ context 'with AWS KMS provider' do
220
+ include_context 'with AWS kms_providers'
221
+
222
+ context 'with collection validator' do
223
+ include_context 'with jsonSchema collection validator'
224
+ it_behaves_like 'a functioning encrypter'
225
+ end
226
+
227
+ context 'with schema map' do
228
+ include_context 'with local schema map'
229
+ it_behaves_like 'a functioning encrypter'
230
+ end
231
+ end
232
+ end
233
+ end