familia 2.0.0.pre19 → 2.0.0.pre21

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 (372) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/claude-code-review.yml +4 -9
  3. data/.github/workflows/code-smells.yml +64 -3
  4. data/.pre-commit-config.yaml +8 -6
  5. data/.reek.yml +10 -9
  6. data/.rubocop.yml +4 -0
  7. data/CHANGELOG.rst +177 -112
  8. data/CLAUDE.md +28 -1
  9. data/Gemfile +1 -1
  10. data/Gemfile.lock +20 -17
  11. data/bin/try +16 -0
  12. data/bin/tryouts +16 -0
  13. data/changelog.d/20251105_flexible_external_identifier_format.rst +66 -0
  14. data/changelog.d/20251107_112554_delano_179_participation_asymmetry.rst +44 -0
  15. data/changelog.d/20251107_213121_delano_fix_thread_safety_races_011CUumCP492Twxm4NLt2FvL.rst +20 -0
  16. data/changelog.d/20251107_fix_participates_in_symbol_resolution.rst +91 -0
  17. data/changelog.d/20251107_optimized_redis_exists_checks.rst +94 -0
  18. data/changelog.d/20251108_frozen_string_literal_pragma.rst +44 -0
  19. data/docs/1106-participates_in-bidirectional-solution.md +129 -0
  20. data/docs/guides/encryption.md +486 -0
  21. data/docs/guides/feature-encrypted-fields.md +123 -7
  22. data/docs/guides/feature-expiration.md +161 -117
  23. data/docs/guides/feature-external-identifiers.md +415 -443
  24. data/docs/guides/feature-object-identifiers.md +400 -269
  25. data/docs/guides/feature-quantization.md +120 -6
  26. data/docs/guides/feature-relationships-indexing.md +318 -0
  27. data/docs/guides/feature-relationships-methods.md +146 -604
  28. data/docs/guides/feature-relationships-participation.md +263 -0
  29. data/docs/guides/feature-relationships.md +118 -136
  30. data/docs/guides/feature-system-devs.md +176 -693
  31. data/docs/guides/feature-system.md +119 -6
  32. data/docs/guides/feature-transient-fields.md +81 -0
  33. data/docs/guides/field-system.md +778 -0
  34. data/docs/guides/index.md +32 -15
  35. data/docs/guides/logging.md +187 -0
  36. data/docs/guides/optimized-loading.md +674 -0
  37. data/docs/guides/thread-safety-monitoring.md +61 -0
  38. data/docs/guides/{time-utilities.md → time-literals.md} +12 -12
  39. data/docs/migrating/v2.0.0-pre22.md +241 -0
  40. data/docs/overview.md +7 -9
  41. data/docs/reference/api-technical.md +267 -320
  42. data/examples/autoloader/mega_customer/features/deprecated_fields.rb +2 -0
  43. data/examples/autoloader/mega_customer/safe_dump_fields.rb +2 -0
  44. data/examples/autoloader/mega_customer.rb +2 -0
  45. data/examples/datatype_standalone.rb +4 -3
  46. data/examples/encrypted_fields.rb +2 -1
  47. data/examples/json_usage_patterns.rb +2 -0
  48. data/examples/relationships.rb +3 -0
  49. data/examples/safe_dump.rb +2 -1
  50. data/examples/sampling_demo.rb +53 -0
  51. data/examples/single_connection_transaction_confusions.rb +2 -1
  52. data/familia.gemspec +2 -1
  53. data/lib/familia/base.rb +2 -0
  54. data/lib/familia/connection/behavior.rb +2 -0
  55. data/lib/familia/connection/handlers.rb +2 -0
  56. data/lib/familia/connection/individual_command_proxy.rb +2 -0
  57. data/lib/familia/connection/middleware.rb +34 -24
  58. data/lib/familia/connection/operation_core.rb +2 -0
  59. data/lib/familia/connection/operations.rb +2 -0
  60. data/lib/familia/connection/pipelined_core.rb +2 -0
  61. data/lib/familia/connection/transaction_core.rb +68 -0
  62. data/lib/familia/connection.rb +18 -3
  63. data/lib/familia/data_type/class_methods.rb +3 -1
  64. data/lib/familia/data_type/connection.rb +2 -0
  65. data/lib/familia/data_type/database_commands.rb +2 -0
  66. data/lib/familia/data_type/serialization.rb +6 -4
  67. data/lib/familia/data_type/settings.rb +2 -0
  68. data/lib/familia/data_type/types/counter.rb +2 -0
  69. data/lib/familia/data_type/types/hashkey.rb +7 -5
  70. data/lib/familia/data_type/types/listkey.rb +2 -0
  71. data/lib/familia/data_type/types/lock.rb +2 -0
  72. data/lib/familia/data_type/types/sorted_set.rb +2 -0
  73. data/lib/familia/data_type/types/stringkey.rb +2 -0
  74. data/lib/familia/data_type/types/unsorted_set.rb +2 -0
  75. data/lib/familia/data_type.rb +2 -0
  76. data/lib/familia/encryption/encrypted_data.rb +4 -2
  77. data/lib/familia/encryption/manager.rb +2 -0
  78. data/lib/familia/encryption/provider.rb +2 -0
  79. data/lib/familia/encryption/providers/aes_gcm_provider.rb +2 -0
  80. data/lib/familia/encryption/providers/secure_xchacha20_poly1305_provider.rb +2 -0
  81. data/lib/familia/encryption/providers/xchacha20_poly1305_provider.rb +2 -0
  82. data/lib/familia/encryption/registry.rb +2 -0
  83. data/lib/familia/encryption/request_cache.rb +2 -0
  84. data/lib/familia/encryption.rb +9 -2
  85. data/lib/familia/errors.rb +2 -0
  86. data/lib/familia/features/autoloader.rb +2 -0
  87. data/lib/familia/features/encrypted_fields/concealed_string.rb +2 -0
  88. data/lib/familia/features/encrypted_fields/encrypted_field_type.rb +4 -0
  89. data/lib/familia/features/encrypted_fields.rb +2 -2
  90. data/lib/familia/features/expiration/extensions.rb +3 -1
  91. data/lib/familia/features/expiration.rb +12 -4
  92. data/lib/familia/features/external_identifier.rb +33 -7
  93. data/lib/familia/features/object_identifier.rb +2 -0
  94. data/lib/familia/features/quantization.rb +3 -1
  95. data/lib/familia/features/relationships/README.md +3 -1
  96. data/lib/familia/features/relationships/collection_operations.rb +2 -0
  97. data/lib/familia/features/relationships/indexing/multi_index_generators.rb +138 -9
  98. data/lib/familia/features/relationships/indexing/rebuild_strategies.rb +479 -0
  99. data/lib/familia/features/relationships/indexing/unique_index_generators.rb +89 -21
  100. data/lib/familia/features/relationships/indexing.rb +3 -0
  101. data/lib/familia/features/relationships/indexing_relationship.rb +3 -1
  102. data/lib/familia/features/relationships/participation/participant_methods.rb +131 -14
  103. data/lib/familia/features/relationships/participation/rebuild_strategies.md +41 -0
  104. data/lib/familia/features/relationships/participation/target_methods.rb +6 -6
  105. data/lib/familia/features/relationships/participation.rb +155 -69
  106. data/lib/familia/features/relationships/participation_membership.rb +69 -0
  107. data/lib/familia/features/relationships/participation_relationship.rb +34 -6
  108. data/lib/familia/features/relationships/score_encoding.rb +2 -0
  109. data/lib/familia/features/relationships.rb +5 -3
  110. data/lib/familia/features/safe_dump.rb +2 -0
  111. data/lib/familia/features/transient_fields/redacted_string.rb +2 -0
  112. data/lib/familia/features/transient_fields/single_use_redacted_string.rb +2 -0
  113. data/lib/familia/features/transient_fields/transient_field_type.rb +5 -3
  114. data/lib/familia/features/transient_fields.rb +2 -0
  115. data/lib/familia/features.rb +2 -0
  116. data/lib/familia/field_type.rb +3 -1
  117. data/lib/familia/horreum/connection.rb +17 -1
  118. data/lib/familia/horreum/database_commands.rb +2 -0
  119. data/lib/familia/horreum/definition.rb +16 -6
  120. data/lib/familia/horreum/management.rb +212 -42
  121. data/lib/familia/horreum/persistence.rb +176 -108
  122. data/lib/familia/horreum/related_fields.rb +2 -0
  123. data/lib/familia/horreum/serialization.rb +23 -4
  124. data/lib/familia/horreum/settings.rb +2 -0
  125. data/lib/familia/horreum/utils.rb +2 -0
  126. data/lib/familia/horreum.rb +15 -1
  127. data/lib/familia/identifier_extractor.rb +2 -0
  128. data/lib/familia/instrumentation.rb +156 -0
  129. data/lib/familia/json_serializer.rb +2 -0
  130. data/lib/familia/logging.rb +92 -32
  131. data/lib/familia/refinements/dear_json.rb +2 -0
  132. data/lib/familia/refinements/stylize_words.rb +2 -14
  133. data/lib/familia/refinements/time_literals.rb +2 -0
  134. data/lib/familia/refinements.rb +2 -0
  135. data/lib/familia/secure_identifier.rb +10 -2
  136. data/lib/familia/settings.rb +2 -0
  137. data/lib/familia/thread_safety/instrumented_mutex.rb +166 -0
  138. data/lib/familia/thread_safety/monitor.rb +328 -0
  139. data/lib/familia/utils.rb +13 -0
  140. data/lib/familia/verifiable_identifier.rb +3 -1
  141. data/lib/familia/version.rb +3 -1
  142. data/lib/familia.rb +31 -4
  143. data/lib/middleware/database_command_counter.rb +152 -0
  144. data/lib/middleware/database_logger.rb +295 -170
  145. data/lib/multi_result.rb +2 -0
  146. data/try/edge_cases/empty_identifiers_try.rb +2 -0
  147. data/try/edge_cases/hash_symbolization_try.rb +2 -0
  148. data/try/edge_cases/json_serialization_try.rb +2 -0
  149. data/try/edge_cases/legacy_data_detection/deserialization_edge_cases_try.rb +4 -0
  150. data/try/edge_cases/race_conditions_try.rb +4 -0
  151. data/try/edge_cases/reserved_keywords_try.rb +4 -0
  152. data/try/edge_cases/string_coercion_try.rb +2 -0
  153. data/try/edge_cases/ttl_side_effects_try.rb +4 -0
  154. data/try/features/encrypted_fields/aad_protection_try.rb +4 -0
  155. data/try/features/encrypted_fields/concealed_string_core_try.rb +4 -0
  156. data/try/features/encrypted_fields/context_isolation_try.rb +4 -0
  157. data/try/features/encrypted_fields/encrypted_fields_core_try.rb +33 -0
  158. data/try/features/encrypted_fields/encrypted_fields_integration_try.rb +4 -0
  159. data/try/features/encrypted_fields/encrypted_fields_no_cache_security_try.rb +4 -0
  160. data/try/features/encrypted_fields/encrypted_fields_security_try.rb +4 -0
  161. data/try/features/encrypted_fields/error_conditions_try.rb +4 -0
  162. data/try/features/encrypted_fields/fresh_key_derivation_try.rb +4 -0
  163. data/try/features/encrypted_fields/fresh_key_try.rb +4 -0
  164. data/try/features/encrypted_fields/key_rotation_try.rb +4 -0
  165. data/try/features/encrypted_fields/memory_security_try.rb +4 -0
  166. data/try/features/encrypted_fields/missing_current_key_version_try.rb +4 -0
  167. data/try/features/encrypted_fields/nonce_uniqueness_try.rb +4 -0
  168. data/try/features/encrypted_fields/secure_by_default_behavior_try.rb +4 -0
  169. data/try/features/encrypted_fields/thread_safety_try.rb +4 -0
  170. data/try/features/encrypted_fields/universal_serialization_safety_try.rb +4 -0
  171. data/try/features/encryption/config_persistence_try.rb +4 -0
  172. data/try/features/encryption/core_try.rb +4 -0
  173. data/try/features/encryption/instance_variable_scope_try.rb +4 -0
  174. data/try/features/encryption/module_loading_try.rb +4 -0
  175. data/try/features/encryption/providers/aes_gcm_provider_try.rb +4 -0
  176. data/try/features/encryption/providers/xchacha20_poly1305_provider_try.rb +4 -0
  177. data/try/features/encryption/roundtrip_validation_try.rb +4 -0
  178. data/try/features/encryption/secure_memory_handling_try.rb +4 -0
  179. data/try/features/expiration/expiration_try.rb +4 -0
  180. data/try/features/external_identifier/external_identifier_try.rb +171 -8
  181. data/try/features/feature_dependencies_try.rb +2 -0
  182. data/try/features/feature_improvements_try.rb +2 -0
  183. data/try/features/field_groups_try.rb +2 -0
  184. data/try/features/object_identifier/object_identifier_integration_try.rb +12 -9
  185. data/try/features/object_identifier/object_identifier_try.rb +2 -0
  186. data/try/features/quantization/quantization_try.rb +4 -0
  187. data/try/features/real_feature_integration_try.rb +2 -0
  188. data/try/features/relationships/indexing_commands_verification_try.rb +2 -0
  189. data/try/features/relationships/indexing_rebuild_try.rb +600 -0
  190. data/try/features/relationships/indexing_try.rb +2 -0
  191. data/try/features/relationships/participation_bidirectional_try.rb +242 -0
  192. data/try/features/relationships/participation_commands_verification_spec.rb +4 -0
  193. data/try/features/relationships/participation_commands_verification_try.rb +2 -0
  194. data/try/features/relationships/participation_performance_improvements_try.rb +11 -9
  195. data/try/features/relationships/participation_reverse_index_try.rb +15 -13
  196. data/try/features/relationships/participation_target_class_resolution_try.rb +209 -0
  197. data/try/features/relationships/participation_unresolved_target_try.rb +109 -0
  198. data/try/features/relationships/relationships_api_changes_try.rb +2 -0
  199. data/try/features/relationships/relationships_edge_cases_try.rb +4 -0
  200. data/try/features/relationships/relationships_performance_minimal_try.rb +4 -0
  201. data/try/features/relationships/relationships_performance_simple_try.rb +4 -0
  202. data/try/features/relationships/relationships_performance_try.rb +4 -0
  203. data/try/features/relationships/relationships_performance_working_try.rb +4 -0
  204. data/try/features/relationships/relationships_try.rb +6 -4
  205. data/try/features/safe_dump/safe_dump_advanced_try.rb +4 -0
  206. data/try/features/safe_dump/safe_dump_try.rb +4 -0
  207. data/try/features/transient_fields/redacted_string_try.rb +2 -0
  208. data/try/features/transient_fields/refresh_reset_try.rb +3 -0
  209. data/try/features/transient_fields/simple_refresh_test.rb +3 -0
  210. data/try/features/transient_fields/single_use_redacted_string_try.rb +2 -0
  211. data/try/features/transient_fields/transient_fields_core_try.rb +4 -0
  212. data/try/features/transient_fields/transient_fields_integration_try.rb +4 -0
  213. data/try/integration/connection/fiber_context_preservation_try.rb +4 -0
  214. data/try/integration/connection/handler_constraints_try.rb +4 -0
  215. data/try/integration/connection/isolated_dbclient_try.rb +4 -0
  216. data/try/integration/connection/middleware_reconnect_try.rb +2 -0
  217. data/try/integration/connection/operation_mode_guards_try.rb +4 -0
  218. data/try/integration/connection/pipeline_fallback_integration_try.rb +3 -0
  219. data/try/integration/connection/pools_try.rb +4 -0
  220. data/try/integration/connection/responsibility_chain_tracking_try.rb +4 -0
  221. data/try/integration/connection/transaction_fallback_integration_try.rb +4 -0
  222. data/try/integration/connection/transaction_mode_permissive_try.rb +4 -0
  223. data/try/integration/connection/transaction_mode_strict_try.rb +4 -0
  224. data/try/integration/connection/transaction_mode_warn_try.rb +4 -0
  225. data/try/integration/connection/transaction_modes_try.rb +4 -0
  226. data/try/integration/conventional_inheritance_try.rb +4 -0
  227. data/try/integration/create_method_try.rb +4 -0
  228. data/try/integration/cross_component_try.rb +4 -0
  229. data/try/integration/data_types/datatype_pipelines_try.rb +4 -0
  230. data/try/integration/data_types/datatype_transactions_try.rb +4 -0
  231. data/try/integration/database_consistency_try.rb +4 -0
  232. data/try/integration/familia_extended_try.rb +4 -0
  233. data/try/integration/familia_members_methods_try.rb +4 -0
  234. data/try/integration/models/customer_safe_dump_try.rb +4 -0
  235. data/try/integration/models/customer_try.rb +4 -0
  236. data/try/integration/models/datatype_base_try.rb +4 -0
  237. data/try/integration/models/familia_object_try.rb +4 -0
  238. data/try/integration/persistence_operations_try.rb +4 -0
  239. data/try/integration/relationships_persistence_round_trip_try.rb +17 -14
  240. data/try/integration/save_methods_consistency_try.rb +241 -0
  241. data/try/integration/scenarios_try.rb +4 -0
  242. data/try/integration/secure_identifier_try.rb +4 -0
  243. data/try/integration/transaction_safety_core_try.rb +176 -0
  244. data/try/integration/transaction_safety_workflow_try.rb +291 -0
  245. data/try/integration/verifiable_identifier_try.rb +4 -0
  246. data/try/investigation/pipeline_routing/README.md +228 -0
  247. data/try/performance/benchmarks_try.rb +4 -0
  248. data/try/performance/transaction_safety_benchmark_try.rb +238 -0
  249. data/try/support/benchmarks/deserialization_benchmark.rb +3 -1
  250. data/try/support/benchmarks/deserialization_correctness_test.rb +3 -1
  251. data/try/support/debugging/cache_behavior_tracer.rb +4 -0
  252. data/try/support/debugging/debug_aad_process.rb +3 -0
  253. data/try/support/debugging/debug_concealed_internal.rb +3 -0
  254. data/try/support/debugging/debug_concealed_reveal.rb +3 -0
  255. data/try/support/debugging/debug_context_aad.rb +3 -0
  256. data/try/support/debugging/debug_context_simple.rb +3 -0
  257. data/try/support/debugging/debug_cross_context.rb +3 -0
  258. data/try/support/debugging/debug_database_load.rb +3 -0
  259. data/try/support/debugging/debug_encrypted_json_check.rb +3 -0
  260. data/try/support/debugging/debug_encrypted_json_step_by_step.rb +3 -0
  261. data/try/support/debugging/debug_exists_lifecycle.rb +3 -0
  262. data/try/support/debugging/debug_field_decrypt.rb +3 -0
  263. data/try/support/debugging/debug_fresh_cross_context.rb +3 -0
  264. data/try/support/debugging/debug_load_path.rb +3 -0
  265. data/try/support/debugging/debug_method_definition.rb +3 -0
  266. data/try/support/debugging/debug_method_resolution.rb +3 -0
  267. data/try/support/debugging/debug_minimal.rb +3 -0
  268. data/try/support/debugging/debug_provider.rb +3 -0
  269. data/try/support/debugging/debug_secure_behavior.rb +3 -0
  270. data/try/support/debugging/debug_string_class.rb +3 -0
  271. data/try/support/debugging/debug_test.rb +3 -0
  272. data/try/support/debugging/debug_test_design.rb +3 -0
  273. data/try/support/debugging/encryption_method_tracer.rb +4 -0
  274. data/try/support/debugging/provider_diagnostics.rb +4 -0
  275. data/try/support/helpers/test_cleanup.rb +4 -0
  276. data/try/support/helpers/test_helpers.rb +5 -0
  277. data/try/support/memory/memory_basic_test.rb +4 -0
  278. data/try/support/memory/memory_detailed_test.rb +4 -0
  279. data/try/support/memory/memory_search_for_string.rb +4 -0
  280. data/try/support/memory/test_actual_redactedstring_protection.rb +4 -0
  281. data/try/support/prototypes/atomic_saves_v1_context_proxy.rb +4 -0
  282. data/try/support/prototypes/atomic_saves_v2_connection_switching.rb +4 -0
  283. data/try/support/prototypes/atomic_saves_v3_connection_pool.rb +4 -0
  284. data/try/support/prototypes/atomic_saves_v4.rb +4 -0
  285. data/try/support/prototypes/lib/atomic_saves_v2_connection_switching_helpers.rb +4 -0
  286. data/try/support/prototypes/lib/atomic_saves_v3_connection_pool_helpers.rb +4 -0
  287. data/try/support/prototypes/pooling/configurable_stress_test.rb +4 -0
  288. data/try/support/prototypes/pooling/lib/atomic_saves_v3_connection_pool_helpers.rb +4 -0
  289. data/try/support/prototypes/pooling/lib/connection_pool_metrics.rb +4 -0
  290. data/try/support/prototypes/pooling/lib/connection_pool_stress_test.rb +4 -0
  291. data/try/support/prototypes/pooling/lib/connection_pool_threading_models.rb +4 -0
  292. data/try/support/prototypes/pooling/lib/visualize_stress_results.rb +4 -2
  293. data/try/support/prototypes/pooling/pool_siege.rb +4 -2
  294. data/try/support/prototypes/pooling/run_stress_tests.rb +4 -2
  295. data/try/thread_safety/README.md +496 -0
  296. data/try/thread_safety/class_connection_chain_race_try.rb +265 -0
  297. data/try/thread_safety/connection_chain_race_try.rb +148 -0
  298. data/try/thread_safety/encryption_manager_cache_race_try.rb +166 -0
  299. data/try/thread_safety/feature_registry_race_try.rb +226 -0
  300. data/try/thread_safety/fiber_pipeline_isolation_try.rb +235 -0
  301. data/try/thread_safety/fiber_transaction_isolation_try.rb +208 -0
  302. data/try/thread_safety/field_registration_race_try.rb +222 -0
  303. data/try/thread_safety/logger_initialization_race_try.rb +170 -0
  304. data/try/thread_safety/middleware_registration_race_try.rb +154 -0
  305. data/try/thread_safety/module_config_race_try.rb +175 -0
  306. data/try/thread_safety/secure_identifier_cache_race_try.rb +226 -0
  307. data/try/unit/core/autoloader_try.rb +4 -0
  308. data/try/unit/core/base_enhancements_try.rb +4 -0
  309. data/try/unit/core/connection_try.rb +4 -0
  310. data/try/unit/core/errors_try.rb +4 -0
  311. data/try/unit/core/extensions_try.rb +4 -0
  312. data/try/unit/core/familia_logger_try.rb +2 -0
  313. data/try/unit/core/familia_try.rb +4 -0
  314. data/try/unit/core/middleware_sampling_try.rb +335 -0
  315. data/try/unit/core/middleware_test_helpers_bug_try.rb +58 -0
  316. data/try/unit/core/middleware_thread_safety_try.rb +245 -0
  317. data/try/unit/core/middleware_try.rb +4 -0
  318. data/try/unit/core/settings_try.rb +4 -0
  319. data/try/unit/core/time_utils_try.rb +4 -0
  320. data/try/unit/core/tools_try.rb +4 -0
  321. data/try/unit/core/utils_try.rb +37 -0
  322. data/try/unit/data_types/boolean_try.rb +4 -0
  323. data/try/unit/data_types/counter_try.rb +4 -0
  324. data/try/unit/data_types/datatype_base_try.rb +4 -0
  325. data/try/unit/data_types/hash_try.rb +4 -0
  326. data/try/unit/data_types/list_try.rb +4 -0
  327. data/try/unit/data_types/lock_try.rb +4 -0
  328. data/try/unit/data_types/sorted_set_try.rb +4 -0
  329. data/try/unit/data_types/sorted_set_zadd_options_try.rb +4 -0
  330. data/try/unit/data_types/string_try.rb +4 -0
  331. data/try/unit/data_types/unsortedset_try.rb +4 -0
  332. data/try/unit/familia_resolve_class_try.rb +116 -0
  333. data/try/unit/horreum/auto_indexing_on_save_try.rb +5 -1
  334. data/try/unit/horreum/automatic_index_validation_try.rb +2 -0
  335. data/try/unit/horreum/base_try.rb +4 -0
  336. data/try/unit/horreum/class_methods_try.rb +4 -0
  337. data/try/unit/horreum/commands_try.rb +4 -0
  338. data/try/unit/horreum/defensive_initialization_try.rb +4 -0
  339. data/try/unit/horreum/destroy_related_fields_cleanup_try.rb +4 -0
  340. data/try/unit/horreum/enhanced_conflict_handling_try.rb +4 -0
  341. data/try/unit/horreum/field_categories_try.rb +4 -0
  342. data/try/unit/horreum/field_definition_try.rb +4 -0
  343. data/try/unit/horreum/initialization_try.rb +4 -0
  344. data/try/unit/horreum/json_type_preservation_try.rb +2 -0
  345. data/try/unit/horreum/optimized_loading_try.rb +156 -0
  346. data/try/unit/horreum/relations_try.rb +4 -0
  347. data/try/unit/horreum/serialization_persistent_fields_try.rb +4 -0
  348. data/try/unit/horreum/serialization_try.rb +4 -0
  349. data/try/unit/horreum/settings_try.rb +4 -0
  350. data/try/unit/horreum/unique_index_edge_cases_try.rb +4 -0
  351. data/try/unit/horreum/unique_index_guard_validation_try.rb +2 -0
  352. data/try/unit/middleware/database_command_counter_methods_try.rb +139 -0
  353. data/try/unit/middleware/database_logger_methods_try.rb +251 -0
  354. data/try/unit/refinements/dear_json_array_methods_try.rb +4 -0
  355. data/try/unit/refinements/dear_json_hash_methods_try.rb +4 -0
  356. data/try/unit/refinements/time_literals_numeric_methods_try.rb +4 -0
  357. data/try/unit/refinements/time_literals_string_methods_try.rb +4 -0
  358. data/try/unit/thread_safety_monitor_try.rb +149 -0
  359. metadata +72 -17
  360. data/.github/workflows/code-quality.yml +0 -138
  361. data/changelog.d/20251011_012003_delano_159_datatype_transaction_pipeline_support.rst +0 -91
  362. data/changelog.d/20251011_203905_delano_next.rst +0 -30
  363. data/changelog.d/20251011_212633_delano_next.rst +0 -13
  364. data/changelog.d/20251011_221253_delano_next.rst +0 -26
  365. data/docs/archive/FAMILIA_RELATIONSHIPS.md +0 -210
  366. data/docs/archive/FAMILIA_TECHNICAL.md +0 -823
  367. data/docs/archive/FAMILIA_UPDATE.md +0 -226
  368. data/docs/archive/README.md +0 -64
  369. data/docs/archive/api-reference.md +0 -333
  370. data/docs/guides/core-field-system.md +0 -806
  371. data/docs/guides/implementation.md +0 -276
  372. data/docs/guides/security-model.md +0 -183
@@ -1,276 +0,0 @@
1
- # Implementation Guide
2
-
3
- ## Architecture Overview
4
-
5
- The encrypted fields feature uses a modular provider system with field transformation hooks:
6
-
7
- ```
8
- User Input → Field Setter → Provider Selection → Encryption → Valkey/Redis
9
- Valkey/Redis → Algorithm Detection → Decryption → Field Getter → User Output
10
- ```
11
-
12
- ### Provider Architecture
13
-
14
- ```
15
- ┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐
16
- │ Manager │ │ Registry │ │ Providers │
17
- │ │ │ │ │ │
18
- │ - encrypt() │───→│ - get() │───→│ XChaCha20Poly │
19
- │ - decrypt() │ │ - register() │ │ AES-GCM │
20
- │ - derive_key() │ │ - priority │ │ (Future: More) │
21
- └─────────────────┘ └──────────────────┘ └─────────────────┘
22
- ```
23
-
24
- ## Core Components
25
-
26
- ### 1. Registry System
27
-
28
- The Registry manages available encryption providers and selects the best one:
29
-
30
- ```ruby
31
- module Familia::Encryption::Registry
32
- # Auto-register available providers by priority
33
- def self.setup!
34
-
35
- # Get provider instance by algorithm
36
- def self.get(algorithm)
37
-
38
- # Get highest-priority available provider
39
- def self.default_provider
40
- end
41
- ```
42
-
43
- ### 2. Manager Class
44
-
45
- The Manager handles encryption/decryption operations with provider delegation:
46
-
47
- ```ruby
48
- class Familia::Encryption::Manager
49
- # Use specific algorithm or auto-select best
50
- def initialize(algorithm: nil)
51
-
52
- # Encrypt with context-specific key derivation
53
- def encrypt(plaintext, context:, additional_data: nil)
54
-
55
- # Decrypt with automatic algorithm detection
56
- def decrypt(encrypted_json, context:, additional_data: nil)
57
- end
58
- ```
59
-
60
- ### 3. Provider Interface
61
-
62
- All providers implement a common interface:
63
-
64
- ```ruby
65
- class Provider
66
- ALGORITHM = 'algorithm-name'
67
-
68
- def self.available? # Check if dependencies are met
69
- def self.priority # Higher = preferred (XChaCha20: 100, AES: 50)
70
-
71
- def encrypt(plaintext, key, additional_data)
72
- def decrypt(ciphertext, key, nonce, auth_tag, additional_data)
73
- def derive_key(master_key, context)
74
- def generate_nonce
75
- end
76
- ```
77
-
78
- ### 4. Key Derivation
79
-
80
- Each field gets a unique encryption key using provider-specific methods:
81
-
82
- ```
83
- Master Key + Field Context → Provider KDF → Field-Specific Key
84
-
85
- XChaCha20-Poly1305: BLAKE2b with personalization
86
- AES-256-GCM: HKDF-SHA256
87
- ```
88
-
89
- ## Implementation Steps
90
-
91
- ### Step 1: Enable Encryption
92
-
93
- ```ruby
94
- class MyModel < Familia::Horreum
95
- # Add the feature (optional if globally enabled)
96
- feature :encryption
97
-
98
- # Define encrypted fields
99
- encrypted_field :sensitive_data
100
- encrypted_field :api_key
101
- end
102
- ```
103
-
104
- ### Step 2: Configure Keys
105
-
106
- ```ruby
107
- # config/initializers/familia.rb
108
- Familia.configure do |config|
109
- config.encryption_keys = {
110
- v1: ENV['FAMILIA_ENCRYPTION_KEY_V1']
111
- }
112
- config.current_key_version = :v1
113
- end
114
-
115
- # Validate configuration at startup
116
- Familia::Encryption.validate_configuration!
117
- ```
118
-
119
- ### Step 3: Generate Keys
120
-
121
- ```bash
122
- # Generate a secure 256-bit key (32 bytes)
123
- $ openssl rand -base64 32
124
- # => base64_encoded_key_here
125
-
126
- # Add to environment
127
- $ echo "FAMILIA_ENCRYPTION_KEY_V1=base64_encoded_key_here" >> .env
128
- ```
129
-
130
- ### Step 4: Install Optional Dependencies
131
-
132
- For best security and performance, install RbNaCl:
133
-
134
- ```bash
135
- # Add to Gemfile
136
- gem 'rbnacl', '~> 7.1', '>= 7.1.1'
137
-
138
- # Install
139
- $ bundle install
140
- ```
141
-
142
- Without RbNaCl, Familia falls back to OpenSSL AES-256-GCM (still secure but lower priority).
143
-
144
- ## Advanced Usage
145
-
146
- ### Custom Field Names
147
-
148
- ```ruby
149
- encrypted_field :favorite_snack, as: :top_secret_snack_preference
150
- ```
151
-
152
- ### Passphrase Protection
153
-
154
- ```ruby
155
- class Vault < Familia::Horreum
156
- encrypted_field :secret
157
-
158
- def unlock(passphrase)
159
- # Passphrase becomes part of encryption context
160
- self.secret(passphrase_value: passphrase)
161
- end
162
- end
163
- ```
164
-
165
- ### Batch Operations
166
-
167
- ```ruby
168
- # Efficient bulk encryption
169
- customers = Customer.batch_create([
170
- { email: 'user1@example.com', favorite_snack: 'chocolate chip cookies' },
171
- { email: 'user2@example.com', favorite_snack: 'leftover pizza' }
172
- ])
173
- ```
174
-
175
- ## Provider-Specific Features
176
-
177
- ### XChaCha20-Poly1305 Provider (Recommended)
178
-
179
- ```ruby
180
- # Enable with RbNaCl gem
181
- gem 'rbnacl', '~> 7.1'
182
-
183
- # Benefits:
184
- # - Extended nonce (192 bits vs 96 bits)
185
- # - Better resistance to nonce reuse
186
- # - BLAKE2b key derivation with personalization
187
- # - Priority: 100 (highest)
188
- ```
189
-
190
- ### AES-256-GCM Provider (Fallback)
191
-
192
- ```ruby
193
- # Always available with OpenSSL
194
- # - 256-bit keys, 96-bit nonces
195
- # - HKDF-SHA256 key derivation
196
- # - Priority: 50
197
- # - Good compatibility, proven security
198
- ```
199
-
200
- ## Performance Optimization
201
-
202
- ### Provider Benchmarking
203
-
204
- ```ruby
205
- # Compare provider performance
206
- results = Familia::Encryption.benchmark(iterations: 1000)
207
- puts results
208
- # => {
209
- # "xchacha20poly1305" => { time: 0.45, ops_per_sec: 4444, priority: 100 },
210
- # "aes-256-gcm" => { time: 0.52, ops_per_sec: 3846, priority: 50 }
211
- # }
212
- ```
213
-
214
- ### Key Derivation Monitoring
215
-
216
- ```ruby
217
- # Monitor key derivations (should increment with each operation)
218
- puts Familia::Encryption.derivation_count.value
219
- # => 42
220
-
221
- # Reset counter for testing
222
- Familia::Encryption.reset_derivation_count!
223
- ```
224
-
225
- ### Memory Management
226
-
227
- **⚠️ Important**: Ruby provides no memory safety guarantees. See security warnings in provider files.
228
-
229
- - Keys are cleared from variables after use (best effort)
230
- - No protection against memory dumps or GC copying
231
- - Plaintext exists in Ruby strings during processing
232
-
233
- ## Testing
234
-
235
- ```ruby
236
- # Test helper
237
- RSpec.configure do |config|
238
- config.include Familia::EncryptionTestHelpers
239
-
240
- config.around(:each, :encryption) do |example|
241
- with_test_encryption_keys { example.run }
242
- end
243
- end
244
-
245
- # In tests
246
- it "encrypts sensitive fields", :encryption do
247
- user = User.create(favorite_snack: "leftover pizza")
248
-
249
- # Verify encryption in Redis
250
- raw_value = redis.hget(user.dbkey, "favorite_snack")
251
- expect(raw_value).not_to include("leftover pizza")
252
- expect(JSON.parse(raw_value)).to have_key("ciphertext")
253
- end
254
- ```
255
-
256
- ## Troubleshooting
257
-
258
- ### Common Issues
259
-
260
- 1. **"No encryption key configured"**
261
- - Ensure `FAMILIA_ENCRYPTION_KEY` is set
262
- - Check `Familia.config.encryption_keys`
263
-
264
- 2. **"Decryption failed"**
265
- - Verify correct key version
266
- - Check if data was encrypted with different key
267
-
268
- 3. **Performance degradation**
269
- - Enable key caching
270
- - Consider installing libsodium gem
271
-
272
- ## Next Steps
273
-
274
- - [Security Model](Security-Model) - Understand the cryptographic design
275
- - [Key Management](Key-Management) - Rotation and best practices
276
- - [Migrating Guide](Migrating-Guide) - Upgrade existing fields
@@ -1,183 +0,0 @@
1
- # Security Model
2
-
3
- ## Cryptographic Design
4
-
5
- ### Provider-Based Architecture
6
-
7
- Familia uses a modular provider system that automatically selects the best available encryption algorithm:
8
-
9
- ### Encryption Algorithms
10
-
11
- **XChaCha20-Poly1305 Provider (Priority: 100)**
12
- - Requires: `rbnacl` gem (libsodium bindings)
13
- - Key Size: 256 bits (32 bytes)
14
- - Nonce Size: 192 bits (24 bytes) - extended nonce space
15
- - Authentication Tag: 128 bits (16 bytes)
16
- - Key Derivation: BLAKE2b with personalization string
17
-
18
- **AES-256-GCM Provider (Priority: 50)**
19
- - Requires: OpenSSL (always available)
20
- - Key Size: 256 bits (32 bytes)
21
- - Nonce Size: 96 bits (12 bytes) - standard GCM nonce
22
- - Authentication Tag: 128 bits (16 bytes)
23
- - Key Derivation: HKDF-SHA256
24
-
25
- ### Key Derivation
26
-
27
- Each field gets a unique key derived from the master key:
28
-
29
- ```
30
- Field Key = KDF(Master Key, Context)
31
-
32
- Where Context = "ClassName:field_name:record_identifier"
33
- ```
34
-
35
- **Provider-Specific KDF:**
36
- - **XChaCha20-Poly1305**: BLAKE2b with customizable personalization string
37
- - **AES-256-GCM**: HKDF-SHA256 with salt and info parameters
38
-
39
- The personalization string provides cryptographic domain separation:
40
- ```ruby
41
- Familia.configure do |config|
42
- config.encryption_personalization = 'MyApp-2024' # Default: 'Familia'
43
- end
44
- ```
45
-
46
- ### Ciphertext Format
47
-
48
- The encrypted data is stored as JSON with algorithm-specific fields:
49
-
50
- **XChaCha20-Poly1305:**
51
- ```json
52
- {
53
- "algorithm": "xchacha20poly1305",
54
- "nonce": "base64_24_byte_nonce",
55
- "ciphertext": "base64_encrypted_data",
56
- "auth_tag": "base64_16_byte_tag",
57
- "key_version": "v1"
58
- }
59
- ```
60
-
61
- **AES-256-GCM:**
62
- ```json
63
- {
64
- "algorithm": "aes-256-gcm",
65
- "nonce": "base64_12_byte_iv",
66
- "ciphertext": "base64_encrypted_data",
67
- "auth_tag": "base64_16_byte_tag",
68
- "key_version": "v1"
69
- }
70
- ```
71
-
72
- ## Threat Model
73
-
74
- ### Protected Against
75
-
76
- #### Database Compromise
77
- - All sensitive fields encrypted with strong keys
78
- - Attackers see only ciphertext
79
-
80
- #### Field Value Swapping
81
- - Field-specific key derivation prevents cross-field decryption
82
- - Swapped values fail to decrypt
83
-
84
- #### Replay Attacks
85
- - Each encryption uses unique random nonce
86
- - Old values remain valid but are distinct encryptions
87
-
88
- #### Tampering
89
- - Authenticated encryption (Poly1305/GCM)
90
- - Modified ciphertext fails authentication
91
-
92
- ### Not Protected Against
93
-
94
- #### Application Memory Compromise
95
- - Plaintext values exist in Ruby memory
96
- - Mitigation: Use libsodium for memory wiping, minimize plaintext lifetime
97
-
98
- #### Master Key Compromise
99
- - All encrypted data compromised if keys obtained
100
- - Mitigation: Secure key storage, regular rotation, hardware security modules
101
-
102
- #### Side-Channel Attacks
103
- - Key recovery through timing/power analysis
104
- - Mitigation: Libsodium provides constant-time operations
105
-
106
- ## Additional Security Features
107
-
108
- ### Passphrase Protection
109
-
110
- For ultra-sensitive fields, add user passphrases:
111
-
112
- ```ruby
113
- encrypted_field :love_letter
114
-
115
- # Passphrase required for decryption
116
- vault.love_letter(passphrase_value: user_passphrase)
117
- ```
118
-
119
- **How it works:**
120
- 1. Passphrase hashed with SHA-256
121
- 2. Hash included in Additional Authenticated Data (AAD)
122
- 3. Wrong passphrase = authentication failure
123
- 4. Passphrase never stored, only verified
124
-
125
- ### Memory Safety
126
-
127
- **⚠️ Critical Ruby Memory Limitations:**
128
-
129
- Ruby provides **NO** memory safety guarantees for cryptographic secrets. This affects ALL providers:
130
-
131
- - **No secure memory wiping**: Ruby cannot guarantee memory zeroing
132
- - **GC copying**: Garbage collector may copy secrets before cleanup
133
- - **String operations**: Every `.dup`, `+`, or interpolation creates uncontrolled copies
134
- - **Memory dumps**: Secrets may persist in swap files or core dumps
135
- - **Finalizer uncertainty**: `ObjectSpace.define_finalizer` timing is unpredictable
136
-
137
- **Provider-Specific Mitigations:**
138
-
139
- Both providers attempt best-effort memory clearing:
140
- - Call `.clear` on sensitive strings after use
141
- - UnsortedSet variables to `nil` when done
142
- - Use finalizers for cleanup (no guarantees)
143
-
144
- **Recommendation**: For production systems with high-security requirements, consider:
145
- - Hardware Security Modules (HSMs)
146
- - External key management services
147
- - Languages with manual memory management (C, Rust)
148
- - Cryptographic appliances with secure enclaves
149
-
150
- ### RedactedString
151
-
152
- Prevents accidental logging of sensitive data:
153
-
154
- ```ruby
155
- class RedactedString < String
156
- def to_s
157
- '[REDACTED]'
158
- end
159
-
160
- def inspect
161
- '[REDACTED]'
162
- end
163
- end
164
-
165
- # In logs:
166
- logger.info "Love letter: #{user.love_letter}" # => "Love letter: [REDACTED]"
167
- ```
168
-
169
- ## Security Checklist
170
-
171
- ### Development
172
-
173
- - [ ] Never log plaintext sensitive fields
174
- - [ ] Use RedactedString for extra protection
175
- - [ ] Use libsodium for production when possible
176
- - [ ] Validate encryption at startup
177
- - [ ] Test encryption round-trips
178
-
179
- ### Operations
180
-
181
- - [ ] Regular key rotation schedule
182
- - [ ] Monitor decryption failures
183
- - [ ] Log field access patterns for auditing purposes