ibm_db 5.6.1 → 5.7.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/ext/Makefile +13 -9
- data/ext/extconf.rb +176 -110
- data/ext/ibm_db.c +60 -0
- data/ext/ibm_db.o +0 -0
- data/ext/ibm_db.so +0 -0
- data/ext/mkmf.log +6 -6
- data/ext/ruby_ibm_db_cli.c +14 -10
- data/ext/ruby_ibm_db_cli.h +4 -0
- data/ext/ruby_ibm_db_cli.o +0 -0
- data/lib/IBM_DB.rb +2 -2
- data/lib/active_record/connection_adapters/ibm_db_adapter.rb +1254 -277
- data/test/active_record/connection_adapters/fake_legacy_adapter.rb +17 -0
- data/test/active_record/connection_adapters/fake_misleading_legacy_adapter.rb +8 -0
- data/test/activejob/destroy_association_async_job_test.rb +62 -0
- data/test/activejob/destroy_association_async_test.rb +147 -11
- data/test/activejob/job_runtime_test.rb +41 -0
- data/test/activejob/unloadable_base_job.rb +3 -0
- data/test/cases/active_record_schema_test.rb +196 -0
- data/test/cases/active_record_test.rb +21 -0
- data/test/cases/adapter_prevent_writes_test.rb +26 -202
- data/test/cases/adapter_test.rb +592 -82
- data/test/cases/adapters/abstract_mysql_adapter/active_schema_test.rb +210 -0
- data/test/cases/adapters/abstract_mysql_adapter/adapter_prevent_writes_test.rb +111 -0
- data/test/cases/adapters/abstract_mysql_adapter/auto_increment_test.rb +48 -0
- data/test/cases/adapters/abstract_mysql_adapter/bind_parameter_test.rb +91 -0
- data/test/cases/adapters/abstract_mysql_adapter/case_sensitivity_test.rb +65 -0
- data/test/cases/adapters/abstract_mysql_adapter/charset_collation_test.rb +85 -0
- data/test/cases/adapters/abstract_mysql_adapter/connection_test.rb +267 -0
- data/test/cases/adapters/abstract_mysql_adapter/count_deleted_rows_with_lock_test.rb +29 -0
- data/test/cases/adapters/abstract_mysql_adapter/json_test.rb +24 -0
- data/test/cases/adapters/abstract_mysql_adapter/mysql_boolean_test.rb +102 -0
- data/test/cases/adapters/abstract_mysql_adapter/mysql_enum_test.rb +47 -0
- data/test/cases/adapters/abstract_mysql_adapter/mysql_explain_test.rb +71 -0
- data/test/cases/adapters/abstract_mysql_adapter/nested_deadlock_test.rb +191 -0
- data/test/cases/adapters/abstract_mysql_adapter/optimizer_hints_test.rb +69 -0
- data/test/cases/adapters/abstract_mysql_adapter/quoting_test.rb +49 -0
- data/test/cases/adapters/abstract_mysql_adapter/schema_migrations_test.rb +68 -0
- data/test/cases/adapters/abstract_mysql_adapter/schema_test.rb +130 -0
- data/test/cases/adapters/abstract_mysql_adapter/set_test.rb +32 -0
- data/test/cases/adapters/abstract_mysql_adapter/sp_test.rb +39 -0
- data/test/cases/adapters/abstract_mysql_adapter/sql_types_test.rb +16 -0
- data/test/cases/adapters/abstract_mysql_adapter/table_options_test.rb +125 -0
- data/test/cases/adapters/abstract_mysql_adapter/transaction_test.rb +204 -0
- data/test/cases/adapters/abstract_mysql_adapter/unsigned_type_test.rb +77 -0
- data/test/cases/adapters/abstract_mysql_adapter/virtual_column_test.rb +69 -0
- data/test/cases/adapters/abstract_mysql_adapter/warnings_test.rb +109 -0
- data/test/cases/adapters/mysql2/check_constraint_quoting_test.rb +35 -0
- data/test/cases/adapters/mysql2/dbconsole_test.rb +87 -0
- data/test/cases/adapters/mysql2/mysql2_adapter_test.rb +136 -10
- data/test/cases/adapters/mysql2/mysql2_rake_test.rb +433 -0
- data/test/cases/adapters/postgresql/active_schema_test.rb +8 -4
- data/test/cases/adapters/postgresql/array_test.rb +6 -6
- data/test/cases/adapters/postgresql/bind_parameter_test.rb +52 -0
- data/test/cases/adapters/postgresql/bit_string_test.rb +2 -2
- data/test/cases/adapters/postgresql/bytea_test.rb +3 -3
- data/test/cases/adapters/postgresql/case_insensitive_test.rb +1 -1
- data/test/cases/adapters/postgresql/change_schema_test.rb +32 -1
- data/test/cases/adapters/postgresql/cidr_test.rb +17 -0
- data/test/cases/adapters/postgresql/citext_test.rb +7 -1
- data/test/cases/adapters/postgresql/collation_test.rb +1 -1
- data/test/cases/adapters/postgresql/composite_test.rb +1 -1
- data/test/cases/adapters/postgresql/connection_test.rb +43 -36
- data/test/cases/adapters/postgresql/create_unlogged_tables_test.rb +3 -2
- data/test/cases/adapters/postgresql/datatype_test.rb +9 -4
- data/test/cases/adapters/postgresql/date_test.rb +2 -2
- data/test/cases/adapters/postgresql/dbconsole_test.rb +109 -0
- data/test/cases/adapters/postgresql/deferred_constraints_test.rb +55 -0
- data/test/cases/adapters/postgresql/domain_test.rb +1 -1
- data/test/cases/adapters/postgresql/enum_test.rb +208 -8
- data/test/cases/adapters/postgresql/explain_test.rb +25 -6
- data/test/cases/adapters/postgresql/extension_migration_test.rb +51 -9
- data/test/cases/adapters/postgresql/foreign_table_test.rb +3 -3
- data/test/cases/adapters/postgresql/full_text_test.rb +1 -1
- data/test/cases/adapters/postgresql/geometric_test.rb +13 -6
- data/test/cases/adapters/postgresql/hstore_test.rb +22 -32
- data/test/cases/adapters/postgresql/infinity_test.rb +13 -2
- data/test/cases/adapters/postgresql/integer_test.rb +1 -1
- data/test/cases/adapters/postgresql/interval_test.rb +9 -17
- data/test/cases/adapters/postgresql/invertible_migration_test.rb +139 -0
- data/test/cases/adapters/postgresql/json_test.rb +5 -0
- data/test/cases/adapters/postgresql/ltree_test.rb +1 -1
- data/test/cases/adapters/postgresql/money_test.rb +17 -9
- data/test/cases/adapters/postgresql/network_test.rb +13 -1
- data/test/cases/adapters/postgresql/numbers_test.rb +18 -2
- data/test/cases/adapters/postgresql/optimizer_hints_test.rb +9 -9
- data/test/cases/adapters/postgresql/partitions_test.rb +5 -2
- data/test/cases/adapters/postgresql/postgresql_adapter_prevent_writes_test.rb +7 -110
- data/test/cases/adapters/postgresql/postgresql_adapter_test.rb +403 -20
- data/test/cases/adapters/postgresql/postgresql_rake_test.rb +637 -0
- data/test/cases/adapters/postgresql/prepared_statements_disabled_test.rb +1 -1
- data/test/cases/adapters/postgresql/quoting_test.rb +60 -1
- data/test/cases/adapters/postgresql/range_test.rb +185 -21
- data/test/cases/adapters/postgresql/referential_integrity_test.rb +29 -5
- data/test/cases/adapters/postgresql/rename_table_test.rb +35 -8
- data/test/cases/adapters/postgresql/schema_authorization_test.rb +2 -2
- data/test/cases/adapters/postgresql/schema_test.rb +270 -20
- data/test/cases/adapters/postgresql/serial_test.rb +5 -5
- data/test/cases/adapters/postgresql/statement_pool_test.rb +6 -2
- data/test/cases/adapters/postgresql/timestamp_test.rb +122 -5
- data/test/cases/adapters/postgresql/transaction_nested_test.rb +130 -6
- data/test/cases/adapters/postgresql/transaction_test.rb +37 -11
- data/test/cases/adapters/postgresql/type_lookup_test.rb +1 -1
- data/test/cases/adapters/postgresql/uuid_test.rb +77 -9
- data/test/cases/adapters/postgresql/virtual_column_test.rb +114 -0
- data/test/cases/adapters/postgresql/xml_test.rb +1 -1
- data/test/cases/adapters/sqlite3/bind_parameter_test.rb +52 -0
- data/test/cases/adapters/sqlite3/collation_test.rb +1 -1
- data/test/cases/adapters/sqlite3/copy_table_test.rb +28 -7
- data/test/cases/adapters/sqlite3/dbconsole_test.rb +81 -0
- data/test/cases/adapters/sqlite3/explain_test.rb +3 -3
- data/test/cases/adapters/sqlite3/quoting_test.rb +34 -3
- data/test/cases/adapters/sqlite3/sqlite3_adapter_prevent_writes_test.rb +9 -102
- data/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb +727 -72
- data/test/cases/adapters/sqlite3/sqlite3_create_folder_test.rb +6 -3
- data/test/cases/adapters/sqlite3/sqlite_rake_test.rb +264 -0
- data/test/cases/adapters/sqlite3/statement_pool_test.rb +1 -1
- data/test/cases/adapters/sqlite3/transaction_test.rb +6 -3
- data/test/cases/adapters/sqlite3/virtual_column_test.rb +138 -0
- data/test/cases/adapters/sqlite3/virtual_table_test.rb +51 -0
- data/test/cases/adapters/trilogy/dbconsole_test.rb +76 -0
- data/test/cases/adapters/trilogy/trilogy_adapter_test.rb +473 -0
- data/test/cases/adapters/trilogy/trilogy_rake_test.rb +433 -0
- data/test/cases/aggregations_test.rb +16 -0
- data/test/cases/annotate_test.rb +14 -12
- data/test/cases/arel/attributes/attribute_test.rb +86 -47
- data/test/cases/arel/collectors/bind_test.rb +1 -1
- data/test/cases/arel/collectors/composite_test.rb +11 -1
- data/test/cases/arel/collectors/sql_string_test.rb +1 -1
- data/test/cases/arel/collectors/substitute_bind_collector_test.rb +1 -1
- data/test/cases/arel/delete_manager_test.rb +0 -6
- data/test/cases/arel/factory_methods_test.rb +45 -0
- data/test/cases/arel/insert_manager_test.rb +1 -7
- data/test/cases/arel/nodes/as_test.rb +12 -0
- data/test/cases/arel/nodes/ascending_test.rb +1 -1
- data/test/cases/arel/nodes/bin_test.rb +1 -1
- data/test/cases/arel/nodes/bound_sql_literal_test.rb +31 -0
- data/test/cases/arel/nodes/cte_test.rb +46 -0
- data/test/cases/arel/nodes/descending_test.rb +1 -1
- data/test/cases/arel/nodes/equality_test.rb +3 -3
- data/test/cases/arel/nodes/filter_test.rb +37 -0
- data/test/cases/arel/nodes/fragments_test.rb +38 -0
- data/test/cases/arel/nodes/homogeneous_in_test.rb +52 -0
- data/test/cases/arel/nodes/infix_operation_test.rb +1 -1
- data/test/cases/arel/nodes/node_test.rb +1 -1
- data/test/cases/arel/nodes/or_test.rb +2 -2
- data/test/cases/arel/nodes/sql_literal_test.rb +18 -1
- data/test/cases/arel/nodes/table_alias_test.rb +12 -0
- data/test/cases/arel/nodes/unary_operation_test.rb +1 -1
- data/test/cases/arel/nodes/update_statement_test.rb +4 -0
- data/test/cases/arel/nodes_test.rb +3 -2
- data/test/cases/arel/select_manager_test.rb +12 -12
- data/test/cases/arel/support/fake_record.rb +22 -17
- data/test/cases/arel/table_test.rb +15 -25
- data/test/cases/arel/update_manager_test.rb +51 -6
- data/test/cases/arel/visitors/dispatch_contamination_test.rb +1 -1
- data/test/cases/arel/visitors/dot_test.rb +177 -2
- data/test/cases/arel/visitors/mysql_test.rb +49 -1
- data/test/cases/arel/visitors/postgres_test.rb +1 -31
- data/test/cases/arel/visitors/sqlite_test.rb +1 -1
- data/test/cases/arel/visitors/to_sql_test.rb +330 -20
- data/test/cases/assertions/query_assertions_test.rb +136 -0
- data/test/cases/associations/belongs_to_associations_test.rb +502 -41
- data/test/cases/associations/bidirectional_destroy_dependencies_test.rb +1 -1
- data/test/cases/associations/cascaded_eager_loading_test.rb +26 -15
- data/test/cases/associations/eager_load_nested_include_test.rb +1 -1
- data/test/cases/associations/eager_singularization_test.rb +1 -1
- data/test/cases/associations/eager_test.rb +255 -93
- data/test/cases/associations/has_and_belongs_to_many_associations_test.rb +25 -53
- data/test/cases/associations/has_many_associations_test.rb +282 -72
- data/test/cases/associations/has_many_through_associations_test.rb +172 -45
- data/test/cases/associations/has_many_through_disable_joins_associations_test.rb +197 -0
- data/test/cases/associations/has_one_associations_test.rb +160 -29
- data/test/cases/associations/has_one_through_associations_test.rb +64 -15
- data/test/cases/associations/has_one_through_disable_joins_associations_test.rb +82 -0
- data/test/cases/associations/inner_join_association_test.rb +36 -6
- data/test/cases/associations/inverse_associations_test.rb +177 -40
- data/test/cases/associations/join_model_test.rb +17 -12
- data/test/cases/associations/left_outer_join_association_test.rb +14 -3
- data/test/cases/associations/nested_error_test.rb +116 -0
- data/test/cases/associations/nested_through_associations_test.rb +54 -19
- data/test/cases/associations/required_test.rb +1 -1
- data/test/cases/associations_test.rb +1278 -21
- data/test/cases/asynchronous_queries_test.rb +310 -0
- data/test/cases/attribute_methods/read_test.rb +6 -0
- data/test/cases/attribute_methods/time_zone_converter_test.rb +21 -0
- data/test/cases/attribute_methods_test.rb +565 -46
- data/test/cases/attributes_test.rb +42 -1
- data/test/cases/autosave_association_test.rb +645 -92
- data/test/cases/base_prevent_writes_test.rb +28 -159
- data/test/cases/base_test.rb +434 -209
- data/test/cases/batches_test.rb +441 -57
- data/test/cases/binary_test.rb +31 -0
- data/test/cases/bind_parameter_test.rb +107 -16
- data/test/cases/cache_key_test.rb +7 -7
- data/test/cases/calculations_test.rb +541 -110
- data/test/cases/callbacks_test.rb +0 -1
- data/test/cases/clone_test.rb +5 -4
- data/test/cases/coders/yaml_column_test.rb +97 -2
- data/test/cases/collection_cache_key_test.rb +24 -16
- data/test/cases/column_alias_test.rb +2 -8
- data/test/cases/column_definition_test.rb +12 -3
- data/test/cases/comment_test.rb +23 -26
- data/test/cases/connection_adapters/adapter_leasing_test.rb +9 -9
- data/test/cases/connection_adapters/connection_handler_test.rb +145 -99
- data/test/cases/connection_adapters/connection_handlers_multi_db_test.rb +79 -55
- data/test/cases/connection_adapters/connection_handlers_multi_pool_config_test.rb +17 -20
- data/test/cases/connection_adapters/connection_handlers_sharding_db_test.rb +146 -55
- data/test/cases/connection_adapters/connection_swapping_nested_test.rb +136 -23
- data/test/cases/connection_adapters/merge_and_resolve_default_url_config_test.rb +96 -27
- data/test/cases/connection_adapters/mysql_type_lookup_test.rb +5 -5
- data/test/cases/connection_adapters/registration_test.rb +98 -0
- data/test/cases/connection_adapters/schema_cache_test.rb +288 -135
- data/test/cases/connection_adapters/standalone_connection_test.rb +38 -0
- data/test/cases/connection_adapters/statement_pool_test.rb +29 -0
- data/test/cases/connection_adapters/type_lookup_test.rb +12 -24
- data/test/cases/connection_handling_test.rb +210 -0
- data/test/cases/connection_management_test.rb +44 -7
- data/test/cases/connection_pool_test.rb +466 -99
- data/test/cases/core_test.rb +167 -9
- data/test/cases/counter_cache_test.rb +129 -2
- data/test/cases/custom_locking_test.rb +3 -3
- data/test/cases/database_configurations/hash_config_test.rb +149 -13
- data/test/cases/database_configurations/resolver_test.rb +14 -10
- data/test/cases/database_configurations/url_config_test.rb +53 -0
- data/test/cases/database_configurations_test.rb +86 -43
- data/test/cases/database_selector_test.rb +30 -8
- data/test/cases/database_statements_test.rb +10 -14
- data/test/cases/date_time_precision_test.rb +141 -11
- data/test/cases/date_time_test.rb +19 -1
- data/test/cases/defaults_test.rb +107 -41
- data/test/cases/delegated_type_test.rb +69 -9
- data/test/cases/dirty_test.rb +82 -25
- data/test/cases/disconnected_test.rb +10 -9
- data/test/cases/dup_test.rb +26 -6
- data/test/cases/encryption/cipher/aes256_gcm_test.rb +50 -0
- data/test/cases/encryption/cipher_test.rb +65 -0
- data/test/cases/encryption/concurrency_test.rb +27 -0
- data/test/cases/encryption/config_test.rb +21 -0
- data/test/cases/encryption/configurable_test.rb +93 -0
- data/test/cases/encryption/contexts_test.rb +105 -0
- data/test/cases/encryption/derived_secret_key_provider_test.rb +31 -0
- data/test/cases/encryption/deterministic_key_provider_test.rb +11 -0
- data/test/cases/encryption/encryptable_record_api_test.rb +175 -0
- data/test/cases/encryption/encryptable_record_message_pack_serialized_test.rb +42 -0
- data/test/cases/encryption/encryptable_record_test.rb +470 -0
- data/test/cases/encryption/encrypted_fixtures_test.rb +22 -0
- data/test/cases/encryption/encrypting_only_encryptor_test.rb +20 -0
- data/test/cases/encryption/encryption_schemes_test.rb +240 -0
- data/test/cases/encryption/encryptor_test.rb +113 -0
- data/test/cases/encryption/envelope_encryption_key_provider_test.rb +49 -0
- data/test/cases/encryption/extended_deterministic_queries_test.rb +81 -0
- data/test/cases/encryption/helper.rb +152 -0
- data/test/cases/encryption/key_generator_test.rb +55 -0
- data/test/cases/encryption/key_provider_test.rb +57 -0
- data/test/cases/encryption/key_test.rb +17 -0
- data/test/cases/encryption/message_pack_message_serializer_test.rb +70 -0
- data/test/cases/encryption/message_serializer_test.rb +82 -0
- data/test/cases/encryption/message_test.rb +43 -0
- data/test/cases/encryption/null_encryptor_test.rb +21 -0
- data/test/cases/encryption/properties_test.rb +69 -0
- data/test/cases/encryption/read_only_null_encryptor_test.rb +19 -0
- data/test/cases/encryption/scheme_test.rb +58 -0
- data/test/cases/encryption/unencrypted_attributes_test.rb +27 -0
- data/test/cases/encryption/uniqueness_validations_test.rb +65 -0
- data/test/cases/enum_test.rb +374 -72
- data/test/cases/errors_test.rb +7 -4
- data/test/cases/excluding_test.rb +116 -0
- data/test/cases/explain_subscriber_test.rb +6 -1
- data/test/cases/explain_test.rb +119 -10
- data/test/cases/filter_attributes_test.rb +7 -14
- data/test/cases/finder_respond_to_test.rb +3 -3
- data/test/cases/finder_test.rb +357 -72
- data/test/cases/fixture_set/file_test.rb +9 -0
- data/test/cases/fixtures_test.rb +426 -190
- data/test/cases/helper.rb +66 -192
- data/test/cases/hot_compatibility_test.rb +10 -10
- data/test/cases/inheritance_test.rb +51 -61
- data/test/cases/inherited_test.rb +40 -0
- data/test/cases/insert_all_test.rb +419 -9
- data/test/cases/instrumentation_test.rb +202 -30
- data/test/cases/integration_test.rb +25 -7
- data/test/cases/invalid_connection_test.rb +5 -5
- data/test/cases/invertible_migration_test.rb +108 -24
- data/test/cases/json_attribute_test.rb +1 -0
- data/test/cases/json_serialization_test.rb +5 -5
- data/test/cases/json_shared_test_cases.rb +5 -9
- data/test/cases/locking_test.rb +67 -31
- data/test/cases/log_subscriber_test.rb +17 -15
- data/test/cases/marshal_serialization_test.rb +78 -5
- data/test/cases/message_pack_test.rb +91 -0
- data/test/cases/migration/change_schema_test.rb +77 -46
- data/test/cases/migration/change_table_test.rb +129 -114
- data/test/cases/migration/check_constraint_test.rb +192 -10
- data/test/cases/migration/column_attributes_test.rb +4 -9
- data/test/cases/migration/column_positioning_test.rb +2 -2
- data/test/cases/migration/columns_test.rb +118 -4
- data/test/cases/migration/command_recorder_test.rb +181 -14
- data/test/cases/migration/compatibility_test.rb +883 -196
- data/test/cases/migration/create_join_table_test.rb +8 -1
- data/test/cases/migration/exclusion_constraint_test.rb +192 -0
- data/test/cases/migration/foreign_key_test.rb +356 -14
- data/test/cases/migration/helper.rb +4 -1
- data/test/cases/migration/index_test.rb +67 -2
- data/test/cases/migration/invalid_options_test.rb +129 -0
- data/test/cases/migration/logger_test.rb +7 -4
- data/test/cases/migration/pending_migrations_test.rb +103 -60
- data/test/cases/migration/references_foreign_key_test.rb +73 -4
- data/test/cases/migration/references_index_test.rb +25 -27
- data/test/cases/migration/references_statements_test.rb +27 -3
- data/test/cases/migration/rename_table_test.rb +39 -54
- data/test/cases/migration/schema_definitions_test.rb +109 -0
- data/test/cases/migration/unique_constraint_test.rb +248 -0
- data/test/cases/migration_test.rb +677 -220
- data/test/cases/migrator_test.rb +102 -75
- data/test/cases/multi_db_migrator_test.rb +55 -34
- data/test/cases/multiparameter_attributes_test.rb +26 -29
- data/test/cases/multiple_db_test.rb +42 -19
- data/test/cases/nested_attributes_test.rb +124 -6
- data/test/cases/nested_attributes_with_callbacks_test.rb +2 -2
- data/test/cases/normalized_attribute_test.rb +117 -0
- data/test/cases/null_relation_test.rb +35 -2
- data/test/cases/persistence/reload_association_cache_test.rb +20 -0
- data/test/cases/persistence_test.rb +629 -22
- data/test/cases/pooled_connections_test.rb +57 -56
- data/test/cases/prepared_statement_status_test.rb +8 -3
- data/test/cases/primary_class_test.rb +134 -0
- data/test/cases/primary_keys_test.rb +171 -55
- data/test/cases/query_cache_test.rb +558 -263
- data/test/cases/query_logs_test.rb +293 -0
- data/test/cases/quoting_test.rb +39 -72
- data/test/cases/readonly_test.rb +50 -12
- data/test/cases/reaper_test.rb +22 -6
- data/test/cases/reflection_test.rb +207 -9
- data/test/cases/relation/and_test.rb +43 -0
- data/test/cases/relation/delegation_test.rb +32 -5
- data/test/cases/relation/delete_all_test.rb +27 -6
- data/test/cases/relation/field_ordered_values_test.rb +128 -0
- data/test/cases/relation/load_async_test.rb +650 -0
- data/test/cases/relation/merging_test.rb +80 -109
- data/test/cases/relation/mutation_test.rb +12 -7
- data/test/cases/relation/or_test.rb +11 -8
- data/test/cases/relation/order_test.rb +90 -0
- data/test/cases/relation/predicate_builder_test.rb +21 -6
- data/test/cases/relation/select_test.rb +162 -3
- data/test/cases/relation/structural_compatibility_test.rb +38 -0
- data/test/cases/relation/update_all_test.rb +81 -27
- data/test/cases/relation/where_chain_test.rb +190 -3
- data/test/cases/relation/where_clause_test.rb +43 -1
- data/test/cases/relation/where_test.rb +95 -7
- data/test/cases/relation/with_test.rb +165 -0
- data/test/cases/relation_test.rb +42 -37
- data/test/cases/relations_test.rb +436 -138
- data/test/cases/reload_models_test.rb +18 -14
- data/test/cases/reserved_word_test.rb +2 -1
- data/test/cases/result_test.rb +14 -22
- data/test/cases/sanitize_test.rb +89 -27
- data/test/cases/schema_dumper_test.rb +535 -62
- data/test/cases/scoping/default_scoping_test.rb +219 -35
- data/test/cases/scoping/named_scoping_test.rb +25 -46
- data/test/cases/scoping/relation_scoping_test.rb +112 -4
- data/test/cases/secure_password_test.rb +108 -0
- data/test/cases/secure_token_test.rb +72 -0
- data/test/cases/serialization_test.rb +1 -1
- data/test/cases/serialized_attribute_test.rb +305 -60
- data/test/cases/shard_keys_test.rb +125 -0
- data/test/cases/shard_selector_test.rb +45 -0
- data/test/cases/signed_id_test.rb +57 -5
- data/test/cases/statement_cache_test.rb +31 -30
- data/test/cases/statement_invalid_test.rb +8 -4
- data/test/cases/store_test.rb +73 -9
- data/test/cases/strict_loading_test.rb +327 -13
- data/test/cases/table_metadata_test.rb +16 -0
- data/test/cases/tasks/database_tasks_test.rb +517 -244
- data/test/cases/test_case.rb +254 -60
- data/test/cases/test_case_test.rb +69 -0
- data/test/cases/test_databases_test.rb +7 -3
- data/test/cases/test_fixtures_test.rb +19 -40
- data/test/cases/time_precision_test.rb +17 -5
- data/test/cases/timestamp_test.rb +124 -16
- data/test/cases/token_for_test.rb +165 -0
- data/test/cases/touch_later_test.rb +43 -1
- data/test/cases/transaction_callbacks_test.rb +325 -8
- data/test/cases/transaction_instrumentation_test.rb +453 -0
- data/test/cases/transaction_isolation_test.rb +12 -8
- data/test/cases/transactions_test.rb +629 -112
- data/test/cases/type/date_time_test.rb +7 -1
- data/test/cases/type/time_test.rb +9 -0
- data/test/cases/type/type_map_test.rb +108 -73
- data/test/cases/type/unsigned_integer_test.rb +12 -0
- data/test/cases/type_caster/connection_test.rb +19 -0
- data/test/cases/type_test.rb +1 -1
- data/test/cases/unconnected_test.rb +7 -7
- data/test/cases/unsafe_raw_sql_test.rb +39 -8
- data/test/cases/validations/absence_validation_test.rb +1 -1
- data/test/cases/validations/association_validation_test.rb +25 -3
- data/test/cases/validations/numericality_validation_test.rb +3 -9
- data/test/cases/validations/presence_validation_test.rb +1 -1
- data/test/cases/validations/uniqueness_validation_test.rb +280 -40
- data/test/cases/validations_test.rb +2 -2
- data/test/cases/view_test.rb +33 -22
- data/test/cases/yaml_serialization_test.rb +23 -17
- data/test/config.example.yml +58 -56
- data/test/config.rb +1 -0
- data/test/fixtures/1_need_quoting.yml +2 -0
- data/test/fixtures/accounts.yml +5 -0
- data/test/fixtures/aircrafts.yml +7 -0
- data/test/fixtures/book_identifiers.yml +11 -0
- data/test/fixtures/books.yml +5 -4
- data/test/fixtures/cake_designers.yml +5 -0
- data/test/fixtures/cars.yml +6 -0
- data/test/fixtures/chefs.yml +5 -0
- data/test/fixtures/clothing_items.yml +23 -0
- data/test/fixtures/clubs.yml +1 -1
- data/test/fixtures/comments.yml +2 -1
- data/test/fixtures/cpk_authors.yml +8 -0
- data/test/fixtures/cpk_books.yml +21 -0
- data/test/fixtures/cpk_order_agreements.yml +13 -0
- data/test/fixtures/cpk_order_tags.yml +15 -0
- data/test/fixtures/cpk_orders.yml +11 -0
- data/test/fixtures/cpk_posts.yml +12 -0
- data/test/fixtures/cpk_reviews.yml +13 -0
- data/test/fixtures/cpk_tags.yml +11 -0
- data/test/fixtures/drink_designers.yml +5 -0
- data/test/fixtures/encrypted_book_that_ignores_cases.yml +4 -0
- data/test/fixtures/encrypted_books.yml +4 -0
- data/test/fixtures/fk_object_to_point_to.yml +2 -0
- data/test/fixtures/memberships.yml +15 -15
- data/test/fixtures/paragraphs.yml +5 -0
- data/test/fixtures/parrots.yml +4 -0
- data/test/fixtures/people.yml +2 -0
- data/test/fixtures/pirates.yml +2 -2
- data/test/fixtures/primary_key_error/primary_key_error.yml +6 -0
- data/test/fixtures/references.yml +3 -3
- data/test/fixtures/sharded_blog_posts.yml +14 -0
- data/test/fixtures/sharded_blog_posts_tags.yml +27 -0
- data/test/fixtures/sharded_blogs.yml +8 -0
- data/test/fixtures/sharded_comments.yml +22 -0
- data/test/fixtures/sharded_tags.yml +34 -0
- data/test/fixtures/sponsors.yml +2 -2
- data/test/fixtures/topics.yml +1 -0
- data/test/fixtures/treasures.yml +4 -0
- data/test/fixtures/virtual_columns.yml +5 -0
- data/test/fixtures/warehouse_things.yml +1 -1
- data/test/migrations/old_and_new_versions/20210716122844_add_people_description.rb +5 -0
- data/test/migrations/old_and_new_versions/20210716123013_add_people_number_of_legs.rb +5 -0
- data/test/migrations/old_and_new_versions/230_add_people_hobby.rb +5 -0
- data/test/migrations/old_and_new_versions/231_add_people_last_name.rb +5 -0
- data/test/migrations/scope/1_unscoped.rb +7 -0
- data/test/migrations/scope/2_mysql_only.mysql.rb +7 -0
- data/test/models/admin/user.rb +2 -0
- data/test/models/admin/user_json.rb +48 -0
- data/test/models/attachment.rb +7 -0
- data/test/models/author.rb +70 -3
- data/test/models/author_encrypted.rb +16 -0
- data/test/models/bird.rb +1 -1
- data/test/models/book.rb +18 -11
- data/test/models/book_destroy_async.rb +1 -1
- data/test/models/book_encrypted.rb +106 -0
- data/test/models/book_identifier.rb +5 -0
- data/test/models/branch.rb +11 -0
- data/test/models/bulb.rb +1 -1
- data/test/models/car.rb +8 -1
- data/test/models/cat.rb +1 -1
- data/test/models/category.rb +3 -1
- data/test/models/chat_message.rb +8 -0
- data/test/models/chef.rb +52 -0
- data/test/models/clothing_item.rb +12 -0
- data/test/models/club.rb +4 -1
- data/test/models/comment.rb +7 -4
- data/test/models/comment_overlapping_counter_cache.rb +15 -0
- data/test/models/company.rb +16 -2
- data/test/models/computer.rb +1 -0
- data/test/models/contact.rb +3 -3
- data/test/models/contract.rb +5 -1
- data/test/models/cpk/author.rb +9 -0
- data/test/models/cpk/book.rb +55 -0
- data/test/models/cpk/book_destroy_async.rb +9 -0
- data/test/models/cpk/car.rb +9 -0
- data/test/models/cpk/car_review.rb +9 -0
- data/test/models/cpk/chapter.rb +16 -0
- data/test/models/cpk/chapter_destroy_async.rb +10 -0
- data/test/models/cpk/comment.rb +9 -0
- data/test/models/cpk/order.rb +55 -0
- data/test/models/cpk/order_agreement.rb +10 -0
- data/test/models/cpk/order_tag.rb +10 -0
- data/test/models/cpk/post.rb +10 -0
- data/test/models/cpk/posts_tag.rb +10 -0
- data/test/models/cpk/review.rb +9 -0
- data/test/models/cpk/tag.rb +10 -0
- data/test/models/cpk.rb +15 -0
- data/test/models/customer.rb +3 -1
- data/test/models/destroy_async_parent.rb +1 -1
- data/test/models/developer.rb +44 -3
- data/test/models/discount.rb +4 -0
- data/test/models/drink_designer.rb +1 -0
- data/test/models/editor.rb +8 -0
- data/test/models/editorship.rb +6 -0
- data/test/models/entry.rb +5 -0
- data/test/models/essay.rb +6 -1
- data/test/models/essay_destroy_async.rb +1 -0
- data/test/models/eye.rb +87 -21
- data/test/models/face.rb +1 -1
- data/test/models/friendship.rb +3 -0
- data/test/models/hardback.rb +7 -0
- data/test/models/hotel.rb +2 -0
- data/test/models/human.rb +2 -2
- data/test/models/invoice.rb +2 -1
- data/test/models/invokes_an_undefined_method.rb +5 -0
- data/test/models/line_item.rb +6 -0
- data/test/models/member.rb +9 -4
- data/test/models/membership.rb +2 -2
- data/test/models/message.rb +2 -1
- data/test/models/need_quoting.rb +5 -0
- data/test/models/paragraph.rb +5 -0
- data/test/models/parrot.rb +6 -3
- data/test/models/person.rb +7 -4
- data/test/models/pirate.rb +4 -1
- data/test/models/pk_autopopulated_by_a_trigger_record.rb +5 -0
- data/test/models/post.rb +65 -2
- data/test/models/post_encrypted.rb +15 -0
- data/test/models/post_with_prefetched_pk.rb +15 -0
- data/test/models/project.rb +1 -0
- data/test/models/publication.rb +16 -0
- data/test/models/raises_argument_error.rb +5 -0
- data/test/models/raises_no_method_error.rb +5 -0
- data/test/models/recipient.rb +5 -0
- data/test/models/reference.rb +1 -1
- data/test/models/reply.rb +1 -1
- data/test/models/room.rb +3 -0
- data/test/models/sharded/blog.rb +12 -0
- data/test/models/sharded/blog_post.rb +17 -0
- data/test/models/sharded/blog_post_destroy_async.rb +14 -0
- data/test/models/sharded/blog_post_tag.rb +11 -0
- data/test/models/sharded/blog_post_with_revision.rb +11 -0
- data/test/models/sharded/comment.rb +12 -0
- data/test/models/sharded/comment_destroy_async.rb +12 -0
- data/test/models/sharded/tag.rb +11 -0
- data/test/models/sharded.rb +8 -0
- data/test/models/ship.rb +1 -1
- data/test/models/shipping_line.rb +11 -0
- data/test/models/subscriber.rb +1 -0
- data/test/models/subscription.rb +3 -1
- data/test/models/too_long_table_name.rb +5 -0
- data/test/models/topic.rb +3 -1
- data/test/models/traffic_light.rb +2 -2
- data/test/models/traffic_light_encrypted.rb +21 -0
- data/test/models/translation.rb +9 -0
- data/test/models/treasure.rb +1 -1
- data/test/models/tyre.rb +1 -1
- data/test/models/user.rb +16 -0
- data/test/models/user_with_invalid_relation.rb +28 -0
- data/test/models/uuid_comment.rb +5 -0
- data/test/models/uuid_entry.rb +5 -0
- data/test/models/uuid_message.rb +5 -0
- data/test/models/zine.rb +2 -1
- data/test/schema/mysql2_specific_schema.rb +26 -12
- data/test/schema/postgresql_specific_schema.rb +121 -13
- data/test/schema/schema.rb +361 -103
- data/test/schema/sqlite_specific_schema.rb +17 -6
- data/test/schema/trilogy_specific_schema.rb +96 -0
- data/test/support/adapter_helper.rb +104 -0
- data/test/support/async_helper.rb +15 -0
- data/test/support/config.rb +1 -1
- data/test/support/connection.rb +14 -2
- data/test/support/ddl_helper.rb +1 -1
- data/test/support/fake_adapter.rb +42 -0
- data/test/support/load_schema_helper.rb +22 -0
- data/test/support/marshal_compatibility_fixtures/IBM_DB/rails_6_1_topic.dump +0 -0
- data/test/support/marshal_compatibility_fixtures/IBM_DB/rails_6_1_topic_associations.dump +0 -0
- data/test/support/marshal_compatibility_fixtures/IBM_DB/rails_7_1_topic.dump +0 -0
- data/test/support/marshal_compatibility_fixtures/IBM_DB/rails_7_1_topic_associations.dump +0 -0
- data/test/support/marshal_compatibility_fixtures/Mysql2/rails_6_1_topic.dump +0 -0
- data/test/support/marshal_compatibility_fixtures/Mysql2/rails_6_1_topic_associations.dump +0 -0
- data/test/support/marshal_compatibility_fixtures/Mysql2/rails_7_1_topic.dump +0 -0
- data/test/support/marshal_compatibility_fixtures/Mysql2/rails_7_1_topic_associations.dump +0 -0
- data/test/support/marshal_compatibility_fixtures/PostgreSQL/rails_6_1_topic.dump +0 -0
- data/test/support/marshal_compatibility_fixtures/PostgreSQL/rails_6_1_topic_associations.dump +0 -0
- data/test/support/marshal_compatibility_fixtures/PostgreSQL/rails_7_1_topic.dump +0 -0
- data/test/support/marshal_compatibility_fixtures/PostgreSQL/rails_7_1_topic_associations.dump +0 -0
- data/test/support/marshal_compatibility_fixtures/SQLite/rails_6_1_topic.dump +0 -0
- data/test/support/marshal_compatibility_fixtures/SQLite/rails_6_1_topic_associations.dump +0 -0
- data/test/support/marshal_compatibility_fixtures/SQLite/rails_7_1_topic.dump +0 -0
- data/test/support/marshal_compatibility_fixtures/SQLite/rails_7_1_topic_associations.dump +0 -0
- data/test/support/marshal_compatibility_fixtures/Trilogy/rails_6_1_topic.dump +0 -0
- data/test/support/marshal_compatibility_fixtures/Trilogy/rails_6_1_topic_associations.dump +0 -0
- data/test/support/marshal_compatibility_fixtures/Trilogy/rails_7_1_topic.dump +0 -0
- data/test/support/marshal_compatibility_fixtures/Trilogy/rails_7_1_topic_associations.dump +0 -0
- data/test/support/schema_dumping_helper.rb +15 -9
- data/test/support/tools.rb +37 -0
- data/test/support/yaml_compatibility_fixtures/rails_4_1_no_symbol.yml +22 -0
- metadata +247 -15
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "cases/encryption/helper"
|
|
4
|
+
require "models/author_encrypted"
|
|
5
|
+
|
|
6
|
+
class ActiveRecord::Encryption::EncryptionSchemesTest < ActiveRecord::EncryptionTestCase
|
|
7
|
+
test "can decrypt encrypted_value encrypted with a different encryption scheme" do
|
|
8
|
+
ActiveRecord::Encryption.config.support_unencrypted_data = false
|
|
9
|
+
|
|
10
|
+
author = create_author_with_name_encrypted_with_previous_scheme
|
|
11
|
+
assert_equal "dhh", author.reload.name
|
|
12
|
+
assert author.encrypted_attribute? :name
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
test "when defining previous encryption schemes, you still get Decryption errors when using invalid clear values" do
|
|
16
|
+
ActiveRecord::Encryption.config.support_unencrypted_data = false
|
|
17
|
+
|
|
18
|
+
author = ActiveRecord::Encryption.without_encryption { EncryptedAuthor.create!(name: "unencrypted author") }
|
|
19
|
+
|
|
20
|
+
assert_raises ActiveRecord::Encryption::Errors::Decryption do
|
|
21
|
+
author.reload.name
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
test "use a custom encryptor" do
|
|
26
|
+
author = EncryptedAuthor1.create name: "1"
|
|
27
|
+
assert_equal "1", author.name
|
|
28
|
+
assert author.encrypted_attribute? :name
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
test "support previous contexts" do
|
|
32
|
+
ActiveRecord::Encryption.config.support_unencrypted_data = true
|
|
33
|
+
|
|
34
|
+
author = EncryptedAuthor2.create name: "2"
|
|
35
|
+
assert_equal "2", author.name
|
|
36
|
+
assert_equal author, EncryptedAuthor2.find_by_name("2")
|
|
37
|
+
assert author.encrypted_attribute? :name
|
|
38
|
+
|
|
39
|
+
Author.find(author.id).update! name: "1"
|
|
40
|
+
assert_equal "1", author.reload.name
|
|
41
|
+
assert_equal author, EncryptedAuthor2.find_by_name("1")
|
|
42
|
+
assert_not author.encrypted_attribute? :name
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
test "use global previous schemes to decrypt data encrypted with previous schemes" do
|
|
46
|
+
ActiveRecord::Encryption.config.support_unencrypted_data = false
|
|
47
|
+
encrypted_author_class = declare_class_with_global_previous_encryption_schemes({ encryptor: TestEncryptor.new("0" => "1") }, { encryptor: TestEncryptor.new("1" => "2") })
|
|
48
|
+
|
|
49
|
+
assert_equal 2, encrypted_author_class.type_for_attribute(:name).previous_types.count
|
|
50
|
+
previous_type_1, previous_type_2 = encrypted_author_class.type_for_attribute(:name).previous_types
|
|
51
|
+
|
|
52
|
+
author = ActiveRecord::Encryption.without_encryption do
|
|
53
|
+
encrypted_author_class.create name: previous_type_1.serialize("1")
|
|
54
|
+
end
|
|
55
|
+
assert_equal "0", author.reload.name
|
|
56
|
+
|
|
57
|
+
author = ActiveRecord::Encryption.without_encryption do
|
|
58
|
+
encrypted_author_class.create name: previous_type_2.serialize("2")
|
|
59
|
+
end
|
|
60
|
+
assert_equal "1", author.reload.name
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
test "use global previous schemes to decrypt data encrypted with previous schemes with unencrypted data" do
|
|
64
|
+
ActiveRecord::Encryption.config.support_unencrypted_data = true
|
|
65
|
+
encrypted_author_class = declare_class_with_global_previous_encryption_schemes({ encryptor: TestEncryptor.new("0" => "1") }, { encryptor: TestEncryptor.new("1" => "2") })
|
|
66
|
+
|
|
67
|
+
assert_equal 3, encrypted_author_class.type_for_attribute(:name).previous_types.count
|
|
68
|
+
previous_type_1, previous_type_2 = encrypted_author_class.type_for_attribute(:name).previous_types
|
|
69
|
+
|
|
70
|
+
author = ActiveRecord::Encryption.without_encryption do
|
|
71
|
+
encrypted_author_class.create name: previous_type_1.serialize("1")
|
|
72
|
+
end
|
|
73
|
+
assert_equal "0", author.reload.name
|
|
74
|
+
|
|
75
|
+
author = ActiveRecord::Encryption.without_encryption do
|
|
76
|
+
encrypted_author_class.create name: previous_type_2.serialize("2")
|
|
77
|
+
end
|
|
78
|
+
assert_equal "1", author.reload.name
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
test "returns ciphertext all the previous schemes fail to decrypt and support for unencrypted data is on" do
|
|
82
|
+
ActiveRecord::Encryption.config.support_unencrypted_data = true
|
|
83
|
+
encrypted_author_class = declare_class_with_global_previous_encryption_schemes({ encryptor: TestEncryptor.new("0" => "1") }, { encryptor: TestEncryptor.new("1" => "2") })
|
|
84
|
+
|
|
85
|
+
author = ActiveRecord::Encryption.without_encryption do
|
|
86
|
+
encrypted_author_class.create name: "some ciphertext"
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
assert_equal "some ciphertext", author.reload.name
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
test "raise decryption error when all the previous schemes fail to decrypt" do
|
|
93
|
+
ActiveRecord::Encryption.config.support_unencrypted_data = false
|
|
94
|
+
encrypted_author_class = declare_class_with_global_previous_encryption_schemes({ encryptor: TestEncryptor.new("0" => "1") }, { encryptor: TestEncryptor.new("1" => "2") })
|
|
95
|
+
|
|
96
|
+
author = ActiveRecord::Encryption.without_encryption do
|
|
97
|
+
encrypted_author_class.create name: "some invalid ciphertext"
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
assert_raise ActiveRecord::Encryption::Errors::Decryption do
|
|
101
|
+
author.reload.name
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
test "deterministic encryption is fixed by default: it will always use the oldest scheme to encrypt data" do
|
|
106
|
+
ActiveRecord::Encryption.config.support_unencrypted_data = false
|
|
107
|
+
ActiveRecord::Encryption.config.deterministic_key = "12345"
|
|
108
|
+
ActiveRecord::Encryption.config.previous = [{ downcase: true, deterministic: true }, { downcase: false, deterministic: true }]
|
|
109
|
+
|
|
110
|
+
encrypted_author_class = Class.new(Author) do
|
|
111
|
+
self.table_name = "authors"
|
|
112
|
+
|
|
113
|
+
encrypts :name, deterministic: true, downcase: false
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
author = encrypted_author_class.create!(name: "STEPHEN KING")
|
|
117
|
+
assert_equal "stephen king", author.name
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
test "don't use global previous schemes with a different deterministic nature" do
|
|
121
|
+
ActiveRecord::Encryption.config.support_unencrypted_data = false
|
|
122
|
+
ActiveRecord::Encryption.config.deterministic_key = "12345"
|
|
123
|
+
ActiveRecord::Encryption.config.previous = [{ downcase: true, deterministic: false }, { downcase: false, deterministic: true }]
|
|
124
|
+
|
|
125
|
+
encrypted_author_class = Class.new(Author) do
|
|
126
|
+
self.table_name = "authors"
|
|
127
|
+
|
|
128
|
+
encrypts :name, deterministic: true, downcase: false
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
author = encrypted_author_class.create!(name: "STEPHEN KING")
|
|
132
|
+
assert_equal "STEPHEN KING", author.name
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
test "deterministic encryption will use the newest encryption scheme to encrypt data when setting it to { fixed: false }" do
|
|
136
|
+
ActiveRecord::Encryption.config.support_unencrypted_data = false
|
|
137
|
+
ActiveRecord::Encryption.config.deterministic_key = "12345"
|
|
138
|
+
ActiveRecord::Encryption.config.previous = [{ downcase: true, deterministic: true }, { downcase: false, deterministic: true }]
|
|
139
|
+
|
|
140
|
+
encrypted_author_class = Class.new(Author) do
|
|
141
|
+
self.table_name = "authors"
|
|
142
|
+
|
|
143
|
+
encrypts :name, deterministic: { fixed: false }, downcase: false
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
author = encrypted_author_class.create!(name: "STEPHEN KING")
|
|
147
|
+
assert_equal "STEPHEN KING", author.name
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
test "use global previous schemes when performing queries" do
|
|
151
|
+
ActiveRecord::Encryption.config.support_unencrypted_data = false
|
|
152
|
+
ActiveRecord::Encryption.config.deterministic_key = "12345"
|
|
153
|
+
ActiveRecord::Encryption.config.previous = [{ downcase: true, deterministic: true }, { downcase: false, deterministic: true }]
|
|
154
|
+
|
|
155
|
+
encrypted_author_class = Class.new(Author) do
|
|
156
|
+
self.table_name = "authors"
|
|
157
|
+
|
|
158
|
+
encrypts :name, deterministic: true, downcase: false
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
author = encrypted_author_class.create!(name: "STEPHEN KING")
|
|
162
|
+
assert_equal author, encrypted_author_class.find_by_name("STEPHEN KING")
|
|
163
|
+
assert_equal author, encrypted_author_class.find_by_name("stephen king")
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
test "don't use global previous schemes with a different deterministic nature when performing queries" do
|
|
167
|
+
ActiveRecord::Encryption.config.support_unencrypted_data = false
|
|
168
|
+
ActiveRecord::Encryption.config.deterministic_key = "12345"
|
|
169
|
+
ActiveRecord::Encryption.config.previous = [{ downcase: true, deterministic: false }, { downcase: false, deterministic: true }]
|
|
170
|
+
|
|
171
|
+
encrypted_author_class = Class.new(Author) do
|
|
172
|
+
self.table_name = "authors"
|
|
173
|
+
|
|
174
|
+
encrypts :name, deterministic: true, downcase: false
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
author = encrypted_author_class.create!(name: "STEPHEN KING")
|
|
178
|
+
assert_equal author, encrypted_author_class.find_by_name("STEPHEN KING")
|
|
179
|
+
assert_nil encrypted_author_class.find_by_name("stephen king")
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
private
|
|
183
|
+
class TestEncryptor
|
|
184
|
+
def initialize(ciphertexts_by_clear_value)
|
|
185
|
+
@ciphertexts_by_clear_value = ciphertexts_by_clear_value
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
def encrypt(clear_text, key_provider: nil, cipher_options: {})
|
|
189
|
+
@ciphertexts_by_clear_value[clear_text] || clear_text
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
def decrypt(encrypted_text, key_provider: nil, cipher_options: {})
|
|
193
|
+
@ciphertexts_by_clear_value.each { |clear_value, encrypted_value| return clear_value if encrypted_value == encrypted_text }
|
|
194
|
+
raise ActiveRecord::Encryption::Errors::Decryption, "Couldn't find a match for #{encrypted_text} (#{@ciphertexts_by_clear_value.inspect})"
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
def encrypted?(text)
|
|
198
|
+
decrypt(text)
|
|
199
|
+
rescue ActiveRecord::Encryption::Errors::Decryption
|
|
200
|
+
false
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
def binary?
|
|
204
|
+
false
|
|
205
|
+
end
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
class EncryptedAuthor1 < Author
|
|
209
|
+
self.table_name = "authors"
|
|
210
|
+
|
|
211
|
+
encrypts :name, encryptor: TestEncryptor.new("1" => "2")
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
class EncryptedAuthor2 < Author
|
|
215
|
+
self.table_name = "authors"
|
|
216
|
+
|
|
217
|
+
encrypts :name, encryptor: TestEncryptor.new("2" => "3"), previous: { encryptor: TestEncryptor.new("1" => "2") }
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
def create_author_with_name_encrypted_with_previous_scheme
|
|
221
|
+
author = EncryptedAuthor.create!(name: "david")
|
|
222
|
+
old_type = EncryptedAuthor.type_for_attribute(:name).previous_types.first
|
|
223
|
+
value_encrypted_with_old_type = old_type.serialize("dhh")
|
|
224
|
+
ActiveRecord::Encryption.without_encryption do
|
|
225
|
+
author.update!(name: value_encrypted_with_old_type)
|
|
226
|
+
end
|
|
227
|
+
author
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
def declare_class_with_global_previous_encryption_schemes(*previous_schemes)
|
|
231
|
+
ActiveRecord::Encryption.config.previous = previous_schemes
|
|
232
|
+
|
|
233
|
+
# We want to evaluate .encrypts *after* tweaking the config property
|
|
234
|
+
Class.new(Author) do
|
|
235
|
+
self.table_name = "authors"
|
|
236
|
+
|
|
237
|
+
encrypts :name
|
|
238
|
+
end.tap { |klass| klass.type_for_attribute(:name) }
|
|
239
|
+
end
|
|
240
|
+
end
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "cases/encryption/helper"
|
|
4
|
+
|
|
5
|
+
class ActiveRecord::Encryption::EncryptorTest < ActiveRecord::EncryptionTestCase
|
|
6
|
+
setup do
|
|
7
|
+
@secret_key = "This is my secret 256 bits key!!"
|
|
8
|
+
@encryptor = ActiveRecord::Encryption::Encryptor.new
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
test "encrypt and decrypt a string" do
|
|
12
|
+
assert_encrypt_text("my secret text")
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
test "trying to decrypt something else than a string will raise a Decryption error" do
|
|
16
|
+
assert_raises(ActiveRecord::Encryption::Errors::Decryption) do
|
|
17
|
+
@encryptor.decrypt(:it_can_only_decrypt_strings)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
test "decrypt an invalid string will raise a Decryption error" do
|
|
22
|
+
assert_raises(ActiveRecord::Encryption::Errors::Decryption) do
|
|
23
|
+
@encryptor.decrypt("some test that does not make sense")
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
test "decrypt an encrypted text with an invalid key will raise a Decryption error" do
|
|
28
|
+
assert_raises(ActiveRecord::Encryption::Errors::Decryption) do
|
|
29
|
+
encrypted_text = @encryptor.encrypt("Some text to encrypt")
|
|
30
|
+
@encryptor.decrypt(encrypted_text, key_provider: ActiveRecord::Encryption::DerivedSecretKeyProvider.new("some invalid key"))
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
test "if an encryption error happens when encrypting an encrypted text it should raise" do
|
|
35
|
+
assert_raises(ActiveRecord::Encryption::Errors::Encryption) do
|
|
36
|
+
key_provider_that_raises_an_encryption_error = ActiveRecord::Encryption::DerivedSecretKeyProvider.new("some key")
|
|
37
|
+
key_provider_that_raises_an_encryption_error.stub :encryption_key, -> { raise ActiveRecord::Encryption::Errors::Encryption } do
|
|
38
|
+
@encryptor.encrypt("Some text to encrypt", key_provider: key_provider_that_raises_an_encryption_error)
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
test "content is compressed" do
|
|
44
|
+
content = SecureRandom.hex(5.kilobytes)
|
|
45
|
+
cipher_text = @encryptor.encrypt(content)
|
|
46
|
+
|
|
47
|
+
assert_encrypt_text content
|
|
48
|
+
assert cipher_text.bytesize < content.bytesize
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
test "content is not compressed, when disabled" do
|
|
52
|
+
@encryptor = ActiveRecord::Encryption::Encryptor.new(compress: false)
|
|
53
|
+
content = SecureRandom.hex(5.kilobytes)
|
|
54
|
+
cipher_text = @encryptor.encrypt(content)
|
|
55
|
+
|
|
56
|
+
assert_encrypt_text content
|
|
57
|
+
assert cipher_text.bytesize > content.bytesize
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
test "trying to encrypt custom classes raises a ForbiddenClass exception" do
|
|
61
|
+
assert_raises ActiveRecord::Encryption::Errors::ForbiddenClass do
|
|
62
|
+
@encryptor.encrypt(Struct.new(:name).new("Jorge"))
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
test "store custom metadata with the encrypted data, accessible by the key provider" do
|
|
67
|
+
key = ActiveRecord::Encryption::Key.new(@secret_key)
|
|
68
|
+
key.public_tags[:key] = "my tag"
|
|
69
|
+
key_provider = ActiveRecord::Encryption::KeyProvider.new(key)
|
|
70
|
+
encryptor = ActiveRecord::Encryption::Encryptor.new
|
|
71
|
+
|
|
72
|
+
key_provider.stub :decryption_keys, ->(message) { [key] } do
|
|
73
|
+
decrypted_text = encryptor.decrypt encryptor.encrypt("some text", key_provider: key_provider), key_provider: key_provider
|
|
74
|
+
assert decrypted_text
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
test "encrypted? returns whether the passed text is encrypted" do
|
|
79
|
+
assert @encryptor.encrypted?(@encryptor.encrypt("clean text"))
|
|
80
|
+
assert_not @encryptor.encrypted?("clean text")
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
test "decrypt respects encoding even when compression is used" do
|
|
84
|
+
text = "The Starfleet is here #{'OMG! ' * 50}!".dup.force_encoding(Encoding::ISO_8859_1)
|
|
85
|
+
encrypted_text = @encryptor.encrypt(text)
|
|
86
|
+
decrypted_text = @encryptor.decrypt(encrypted_text)
|
|
87
|
+
|
|
88
|
+
assert_equal Encoding::ISO_8859_1, decrypted_text.encoding
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
test "accept a custom compressor" do
|
|
92
|
+
compressor = Module.new do
|
|
93
|
+
def self.deflate(data)
|
|
94
|
+
"compressed #{data}"
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def self.inflate(data)
|
|
98
|
+
data.sub(/\Acompressed /, "")
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
@encryptor = ActiveRecord::Encryption::Encryptor.new(compressor: compressor)
|
|
102
|
+
content = SecureRandom.hex(5.kilobytes)
|
|
103
|
+
|
|
104
|
+
assert_encrypt_text content
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
private
|
|
108
|
+
def assert_encrypt_text(clean_text)
|
|
109
|
+
encrypted_text = @encryptor.encrypt(clean_text)
|
|
110
|
+
assert_not_equal encrypted_text, clean_text
|
|
111
|
+
assert_equal clean_text, @encryptor.decrypt(encrypted_text)
|
|
112
|
+
end
|
|
113
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "cases/encryption/helper"
|
|
4
|
+
|
|
5
|
+
class ActiveRecord::Encryption::EnvelopeEncryptionKeyProviderTest < ActiveRecord::EncryptionTestCase
|
|
6
|
+
setup do
|
|
7
|
+
@key_provider = ActiveRecord::Encryption::EnvelopeEncryptionKeyProvider.new
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
test "encryption_key returns random encryption keys" do
|
|
11
|
+
keys = 5.times.collect { @key_provider.encryption_key }
|
|
12
|
+
assert_equal 5, keys.group_by(&:secret).length
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
test "generate_random_encryption_key generates keys of 32 bytes" do
|
|
16
|
+
assert_equal 32, @key_provider.encryption_key.secret.bytesize
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
test "generated random keys carry their secret encrypted with the primary key" do
|
|
20
|
+
key = @key_provider.encryption_key
|
|
21
|
+
encrypted_secret = key.public_tags.encrypted_data_key
|
|
22
|
+
assert_equal key.secret, ActiveRecord::Encryption.cipher.decrypt(encrypted_secret, key: @key_provider.active_primary_key.secret)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
test "decryption_key_for returns the decryption key for a message that was encrypted with a generated encryption key" do
|
|
26
|
+
key = @key_provider.encryption_key
|
|
27
|
+
encrypted_encoded_message = ActiveRecord::Encryption.encryptor.encrypt("some message", key_provider: ActiveRecord::Encryption::KeyProvider.new(key))
|
|
28
|
+
encrypted_message = ActiveRecord::Encryption.message_serializer.load encrypted_encoded_message
|
|
29
|
+
assert_equal key.secret, @key_provider.decryption_keys(encrypted_message).first.secret
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
test "work with multiple keys when config.store_key_references is false" do
|
|
33
|
+
ActiveRecord::Encryption.config.primary_key = ["key 1", "key 2"]
|
|
34
|
+
|
|
35
|
+
assert_encryptor_works_with @key_provider
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
test "work with multiple keys when config.store_key_references is true" do
|
|
39
|
+
ActiveRecord::Encryption.config.primary_key = ["key 1", "key 2"]
|
|
40
|
+
ActiveRecord::Encryption.config.store_key_references = true
|
|
41
|
+
|
|
42
|
+
assert_encryptor_works_with @key_provider
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
private
|
|
46
|
+
def assert_multiple_primary_keys
|
|
47
|
+
assert Rails.application.credentials.dig(:active_record_encryption, :primary_key).length > 1
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "cases/encryption/helper"
|
|
4
|
+
require "models/book_encrypted"
|
|
5
|
+
|
|
6
|
+
class ActiveRecord::Encryption::ExtendedDeterministicQueriesTest < ActiveRecord::EncryptionTestCase
|
|
7
|
+
setup do
|
|
8
|
+
ActiveRecord::Encryption.config.support_unencrypted_data = true
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
test "Finds records when data is unencrypted" do
|
|
12
|
+
UnencryptedBook.create!(name: "Dune")
|
|
13
|
+
assert EncryptedBook.find_by(name: "Dune") # core
|
|
14
|
+
assert EncryptedBook.where("id > 0").find_by(name: "Dune") # relation
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
test "Finds records when data is encrypted" do
|
|
18
|
+
EncryptedBook.create!(name: "Dune")
|
|
19
|
+
assert EncryptedBook.find_by(name: "Dune") # core
|
|
20
|
+
assert EncryptedBook.where("id > 0").find_by(name: "Dune") # relation
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
test "Works well with downcased attributes" do
|
|
24
|
+
EncryptedBookWithDowncaseName.create! name: "Dune"
|
|
25
|
+
assert EncryptedBookWithDowncaseName.find_by(name: "DUNE")
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
test "Works well with string attribute names" do
|
|
29
|
+
UnencryptedBook.create! "name" => "Dune"
|
|
30
|
+
assert EncryptedBook.find_by("name" => "Dune")
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
test "find_or_create_by works" do
|
|
34
|
+
EncryptedBook.find_or_create_by!(name: "Dune")
|
|
35
|
+
assert EncryptedBook.find_by(name: "Dune")
|
|
36
|
+
|
|
37
|
+
EncryptedBook.find_or_create_by!(name: "Dune")
|
|
38
|
+
assert EncryptedBook.find_by(name: "Dune")
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
test "does not mutate arguments" do
|
|
42
|
+
props = { name: "Dune" }
|
|
43
|
+
|
|
44
|
+
assert_equal "Dune", EncryptedBook.find_or_initialize_by(props).name
|
|
45
|
+
assert_equal "Dune", props[:name]
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
test "where(...).first_or_create works" do
|
|
49
|
+
EncryptedBook.where(name: "Dune").first_or_create
|
|
50
|
+
assert EncryptedBook.exists?(name: "Dune")
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
test "exists?(...) works" do
|
|
54
|
+
EncryptedBook.create! name: "Dune"
|
|
55
|
+
assert EncryptedBook.exists?(name: "Dune")
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
test "If support_unencrypted_data is opted out at the attribute level, cannot find unencrypted data" do
|
|
59
|
+
UnencryptedBook.create! name: "Dune"
|
|
60
|
+
assert_nil EncryptedBookWithUnencryptedDataOptedOut.find_by(name: "Dune") # core
|
|
61
|
+
assert_nil EncryptedBookWithUnencryptedDataOptedOut.where("id > 0").find_by(name: "Dune") # relation
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
test "If support_unencrypted_data is opted out at the attribute level, can find encrypted data" do
|
|
65
|
+
EncryptedBook.create! name: "Dune"
|
|
66
|
+
assert EncryptedBookWithUnencryptedDataOptedOut.find_by(name: "Dune") # core
|
|
67
|
+
assert EncryptedBookWithUnencryptedDataOptedOut.where("id > 0").find_by(name: "Dune") # relation
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
test "If support_unencrypted_data is opted in at the attribute level, can find unencrypted data" do
|
|
71
|
+
UnencryptedBook.create! name: "Dune"
|
|
72
|
+
assert EncryptedBookWithUnencryptedDataOptedIn.find_by(name: "Dune") # core
|
|
73
|
+
assert EncryptedBookWithUnencryptedDataOptedIn.where("id > 0").find_by(name: "Dune") # relation
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
test "If support_unencrypted_data is opted in at the attribute level, can find encrypted data" do
|
|
77
|
+
EncryptedBook.create! name: "Dune"
|
|
78
|
+
assert EncryptedBookWithUnencryptedDataOptedIn.find_by(name: "Dune") # core
|
|
79
|
+
assert EncryptedBookWithUnencryptedDataOptedIn.where("id > 0").find_by(name: "Dune") # relation
|
|
80
|
+
end
|
|
81
|
+
end
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "cases/helper"
|
|
4
|
+
|
|
5
|
+
class ActiveRecord::Fixture
|
|
6
|
+
prepend ActiveRecord::Encryption::EncryptedFixtures
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
module ActiveRecord::Encryption
|
|
10
|
+
module EncryptionHelpers
|
|
11
|
+
def assert_ciphertext_decrypts_to(model, attribute_name, ciphertext)
|
|
12
|
+
assert_not_equal model.public_send(attribute_name), ciphertext
|
|
13
|
+
assert_not_equal model.read_attribute(attribute_name), ciphertext
|
|
14
|
+
cleartext = model.type_for_attribute(attribute_name).deserialize(ciphertext)
|
|
15
|
+
assert_equal model.read_attribute(attribute_name), cleartext
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def assert_encrypted_attribute(model, attribute_name, expected_value)
|
|
19
|
+
assert_ciphertext_decrypts_to model, attribute_name, model.read_attribute_before_type_cast(attribute_name)
|
|
20
|
+
assert_equal expected_value, model.public_send(attribute_name)
|
|
21
|
+
unless model.new_record?
|
|
22
|
+
model.reload
|
|
23
|
+
assert_ciphertext_decrypts_to model, attribute_name, model.read_attribute_before_type_cast(attribute_name)
|
|
24
|
+
assert_equal expected_value, model.public_send(attribute_name)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def assert_invalid_key_cant_read_attribute(model, attribute_name)
|
|
29
|
+
if model.type_for_attribute(attribute_name).key_provider.respond_to?(:keys=)
|
|
30
|
+
assert_invalid_key_cant_read_attribute_with_custom_key_provider(model, attribute_name)
|
|
31
|
+
else
|
|
32
|
+
assert_invalid_key_cant_read_attribute_with_default_key_provider(model, attribute_name)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def assert_not_encrypted_attribute(model, attribute_name, expected_value)
|
|
37
|
+
assert_equal expected_value, model.send(attribute_name)
|
|
38
|
+
assert_equal expected_value, model.read_attribute_before_type_cast(attribute_name)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def assert_encrypted_record(model)
|
|
42
|
+
encrypted_attributes = model.class.encrypted_attributes.find_all { |attribute_name| model.send(attribute_name).present? }
|
|
43
|
+
assert_not encrypted_attributes.empty?, "The model has no encrypted attributes with content to check (they are all blank)"
|
|
44
|
+
|
|
45
|
+
encrypted_attributes.each do |attribute_name|
|
|
46
|
+
assert_encrypted_attribute model, attribute_name, model.send(attribute_name)
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def assert_encryptor_works_with(key_provider)
|
|
51
|
+
encryptor = ActiveRecord::Encryption::Encryptor.new
|
|
52
|
+
|
|
53
|
+
encrypted_message = encryptor.encrypt("some text", key_provider: key_provider)
|
|
54
|
+
assert_equal "some text", encryptor.decrypt(encrypted_message, key_provider: key_provider)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
private
|
|
58
|
+
def build_keys(count = 3)
|
|
59
|
+
count.times.collect do |index|
|
|
60
|
+
password = "some secret #{index}"
|
|
61
|
+
secret = ActiveRecord::Encryption.key_generator.derive_key_from(password)
|
|
62
|
+
ActiveRecord::Encryption::Key.new(secret)
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def with_key_provider(key_provider, &block)
|
|
67
|
+
ActiveRecord::Encryption.with_encryption_context key_provider: key_provider, &block
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def with_envelope_encryption(&block)
|
|
71
|
+
@envelope_encryption_key_provider ||= ActiveRecord::Encryption::EnvelopeEncryptionKeyProvider.new
|
|
72
|
+
with_key_provider @envelope_encryption_key_provider, &block
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def create_unencrypted_book_ignoring_case(name:)
|
|
76
|
+
book = ActiveRecord::Encryption.without_encryption do
|
|
77
|
+
EncryptedBookThatIgnoresCase.create!(name: name)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Skip type casting to simulate an upcase value. Not supported in AR without using private apis
|
|
81
|
+
EncryptedBookThatIgnoresCase.lease_connection.execute <<~SQL
|
|
82
|
+
UPDATE encrypted_books SET name = '#{name}' WHERE id = #{book.id};
|
|
83
|
+
SQL
|
|
84
|
+
|
|
85
|
+
book.reload
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def assert_invalid_key_cant_read_attribute_with_default_key_provider(model, attribute_name)
|
|
89
|
+
model.reload
|
|
90
|
+
|
|
91
|
+
ActiveRecord::Encryption.with_encryption_context key_provider: ActiveRecord::Encryption::DerivedSecretKeyProvider.new("a different 256 bits key for now") do
|
|
92
|
+
assert_raises ActiveRecord::Encryption::Errors::Decryption do
|
|
93
|
+
model.public_send(attribute_name)
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def assert_invalid_key_cant_read_attribute_with_custom_key_provider(model, attribute_name)
|
|
99
|
+
attribute_type = model.type_for_attribute(attribute_name)
|
|
100
|
+
|
|
101
|
+
model.reload
|
|
102
|
+
|
|
103
|
+
original_keys = attribute_type.key_provider.keys
|
|
104
|
+
attribute_type.key_provider.keys = [ ActiveRecord::Encryption::Key.derive_from("other custom attribute secret") ]
|
|
105
|
+
|
|
106
|
+
assert_raises ActiveRecord::Encryption::Errors::Decryption do
|
|
107
|
+
model.public_send(attribute_name)
|
|
108
|
+
end
|
|
109
|
+
ensure
|
|
110
|
+
attribute_type.key_provider.keys = original_keys
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# We eager load encrypted attribute types as they are declared, so that they pick up the
|
|
116
|
+
# default encryption setup for tests. Because we load those lazily when used, this prevents
|
|
117
|
+
# side effects where some tests modify encryption config settings affecting others.
|
|
118
|
+
#
|
|
119
|
+
# Notice that we clear the declaration listeners when each test start, so this will only affect
|
|
120
|
+
# the classes loaded before tests starts, not those declared during tests.
|
|
121
|
+
ActiveRecord::Encryption.on_encrypted_attribute_declared do |klass, attribute_name|
|
|
122
|
+
klass.type_for_attribute(attribute_name)
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
class ActiveRecord::EncryptionTestCase < ActiveRecord::TestCase
|
|
126
|
+
include ActiveRecord::Encryption::EncryptionHelpers
|
|
127
|
+
|
|
128
|
+
ENCRYPTION_PROPERTIES_TO_RESET = {
|
|
129
|
+
config: %i[ primary_key deterministic_key key_derivation_salt store_key_references hash_digest_class
|
|
130
|
+
key_derivation_salt support_unencrypted_data encrypt_fixtures
|
|
131
|
+
forced_encoding_for_deterministic_encryption ],
|
|
132
|
+
context: %i[ key_provider ]
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
setup do
|
|
136
|
+
ENCRYPTION_PROPERTIES_TO_RESET.each do |key, properties|
|
|
137
|
+
properties.each do |property|
|
|
138
|
+
instance_variable_set "@_original_encryption_#{key}_#{property}", ActiveRecord::Encryption.public_send(key).public_send(property)
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
ActiveRecord::Encryption.config.previous_schemes.clear
|
|
142
|
+
ActiveRecord::Encryption.encrypted_attribute_declaration_listeners&.clear
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
teardown do
|
|
146
|
+
ENCRYPTION_PROPERTIES_TO_RESET.each do |key, properties|
|
|
147
|
+
properties.each do |property|
|
|
148
|
+
ActiveRecord::Encryption.public_send(key).public_send("#{property}=", instance_variable_get("@_original_encryption_#{key}_#{property}"))
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
end
|