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.
- checksums.yaml +4 -4
- data/.github/workflows/claude-code-review.yml +4 -9
- data/.github/workflows/code-smells.yml +64 -3
- data/.pre-commit-config.yaml +8 -6
- data/.reek.yml +10 -9
- data/.rubocop.yml +4 -0
- data/CHANGELOG.rst +177 -112
- data/CLAUDE.md +28 -1
- data/Gemfile +1 -1
- data/Gemfile.lock +20 -17
- data/bin/try +16 -0
- data/bin/tryouts +16 -0
- data/changelog.d/20251105_flexible_external_identifier_format.rst +66 -0
- data/changelog.d/20251107_112554_delano_179_participation_asymmetry.rst +44 -0
- data/changelog.d/20251107_213121_delano_fix_thread_safety_races_011CUumCP492Twxm4NLt2FvL.rst +20 -0
- data/changelog.d/20251107_fix_participates_in_symbol_resolution.rst +91 -0
- data/changelog.d/20251107_optimized_redis_exists_checks.rst +94 -0
- data/changelog.d/20251108_frozen_string_literal_pragma.rst +44 -0
- data/docs/1106-participates_in-bidirectional-solution.md +129 -0
- data/docs/guides/encryption.md +486 -0
- data/docs/guides/feature-encrypted-fields.md +123 -7
- data/docs/guides/feature-expiration.md +161 -117
- data/docs/guides/feature-external-identifiers.md +415 -443
- data/docs/guides/feature-object-identifiers.md +400 -269
- data/docs/guides/feature-quantization.md +120 -6
- data/docs/guides/feature-relationships-indexing.md +318 -0
- data/docs/guides/feature-relationships-methods.md +146 -604
- data/docs/guides/feature-relationships-participation.md +263 -0
- data/docs/guides/feature-relationships.md +118 -136
- data/docs/guides/feature-system-devs.md +176 -693
- data/docs/guides/feature-system.md +119 -6
- data/docs/guides/feature-transient-fields.md +81 -0
- data/docs/guides/field-system.md +778 -0
- data/docs/guides/index.md +32 -15
- data/docs/guides/logging.md +187 -0
- data/docs/guides/optimized-loading.md +674 -0
- data/docs/guides/thread-safety-monitoring.md +61 -0
- data/docs/guides/{time-utilities.md → time-literals.md} +12 -12
- data/docs/migrating/v2.0.0-pre22.md +241 -0
- data/docs/overview.md +7 -9
- data/docs/reference/api-technical.md +267 -320
- data/examples/autoloader/mega_customer/features/deprecated_fields.rb +2 -0
- data/examples/autoloader/mega_customer/safe_dump_fields.rb +2 -0
- data/examples/autoloader/mega_customer.rb +2 -0
- data/examples/datatype_standalone.rb +4 -3
- data/examples/encrypted_fields.rb +2 -1
- data/examples/json_usage_patterns.rb +2 -0
- data/examples/relationships.rb +3 -0
- data/examples/safe_dump.rb +2 -1
- data/examples/sampling_demo.rb +53 -0
- data/examples/single_connection_transaction_confusions.rb +2 -1
- data/familia.gemspec +2 -1
- data/lib/familia/base.rb +2 -0
- data/lib/familia/connection/behavior.rb +2 -0
- data/lib/familia/connection/handlers.rb +2 -0
- data/lib/familia/connection/individual_command_proxy.rb +2 -0
- data/lib/familia/connection/middleware.rb +34 -24
- data/lib/familia/connection/operation_core.rb +2 -0
- data/lib/familia/connection/operations.rb +2 -0
- data/lib/familia/connection/pipelined_core.rb +2 -0
- data/lib/familia/connection/transaction_core.rb +68 -0
- data/lib/familia/connection.rb +18 -3
- data/lib/familia/data_type/class_methods.rb +3 -1
- data/lib/familia/data_type/connection.rb +2 -0
- data/lib/familia/data_type/database_commands.rb +2 -0
- data/lib/familia/data_type/serialization.rb +6 -4
- data/lib/familia/data_type/settings.rb +2 -0
- data/lib/familia/data_type/types/counter.rb +2 -0
- data/lib/familia/data_type/types/hashkey.rb +7 -5
- data/lib/familia/data_type/types/listkey.rb +2 -0
- data/lib/familia/data_type/types/lock.rb +2 -0
- data/lib/familia/data_type/types/sorted_set.rb +2 -0
- data/lib/familia/data_type/types/stringkey.rb +2 -0
- data/lib/familia/data_type/types/unsorted_set.rb +2 -0
- data/lib/familia/data_type.rb +2 -0
- data/lib/familia/encryption/encrypted_data.rb +4 -2
- data/lib/familia/encryption/manager.rb +2 -0
- data/lib/familia/encryption/provider.rb +2 -0
- data/lib/familia/encryption/providers/aes_gcm_provider.rb +2 -0
- data/lib/familia/encryption/providers/secure_xchacha20_poly1305_provider.rb +2 -0
- data/lib/familia/encryption/providers/xchacha20_poly1305_provider.rb +2 -0
- data/lib/familia/encryption/registry.rb +2 -0
- data/lib/familia/encryption/request_cache.rb +2 -0
- data/lib/familia/encryption.rb +9 -2
- data/lib/familia/errors.rb +2 -0
- data/lib/familia/features/autoloader.rb +2 -0
- data/lib/familia/features/encrypted_fields/concealed_string.rb +2 -0
- data/lib/familia/features/encrypted_fields/encrypted_field_type.rb +4 -0
- data/lib/familia/features/encrypted_fields.rb +2 -2
- data/lib/familia/features/expiration/extensions.rb +3 -1
- data/lib/familia/features/expiration.rb +12 -4
- data/lib/familia/features/external_identifier.rb +33 -7
- data/lib/familia/features/object_identifier.rb +2 -0
- data/lib/familia/features/quantization.rb +3 -1
- data/lib/familia/features/relationships/README.md +3 -1
- data/lib/familia/features/relationships/collection_operations.rb +2 -0
- data/lib/familia/features/relationships/indexing/multi_index_generators.rb +138 -9
- data/lib/familia/features/relationships/indexing/rebuild_strategies.rb +479 -0
- data/lib/familia/features/relationships/indexing/unique_index_generators.rb +89 -21
- data/lib/familia/features/relationships/indexing.rb +3 -0
- data/lib/familia/features/relationships/indexing_relationship.rb +3 -1
- data/lib/familia/features/relationships/participation/participant_methods.rb +131 -14
- data/lib/familia/features/relationships/participation/rebuild_strategies.md +41 -0
- data/lib/familia/features/relationships/participation/target_methods.rb +6 -6
- data/lib/familia/features/relationships/participation.rb +155 -69
- data/lib/familia/features/relationships/participation_membership.rb +69 -0
- data/lib/familia/features/relationships/participation_relationship.rb +34 -6
- data/lib/familia/features/relationships/score_encoding.rb +2 -0
- data/lib/familia/features/relationships.rb +5 -3
- data/lib/familia/features/safe_dump.rb +2 -0
- data/lib/familia/features/transient_fields/redacted_string.rb +2 -0
- data/lib/familia/features/transient_fields/single_use_redacted_string.rb +2 -0
- data/lib/familia/features/transient_fields/transient_field_type.rb +5 -3
- data/lib/familia/features/transient_fields.rb +2 -0
- data/lib/familia/features.rb +2 -0
- data/lib/familia/field_type.rb +3 -1
- data/lib/familia/horreum/connection.rb +17 -1
- data/lib/familia/horreum/database_commands.rb +2 -0
- data/lib/familia/horreum/definition.rb +16 -6
- data/lib/familia/horreum/management.rb +212 -42
- data/lib/familia/horreum/persistence.rb +176 -108
- data/lib/familia/horreum/related_fields.rb +2 -0
- data/lib/familia/horreum/serialization.rb +23 -4
- data/lib/familia/horreum/settings.rb +2 -0
- data/lib/familia/horreum/utils.rb +2 -0
- data/lib/familia/horreum.rb +15 -1
- data/lib/familia/identifier_extractor.rb +2 -0
- data/lib/familia/instrumentation.rb +156 -0
- data/lib/familia/json_serializer.rb +2 -0
- data/lib/familia/logging.rb +92 -32
- data/lib/familia/refinements/dear_json.rb +2 -0
- data/lib/familia/refinements/stylize_words.rb +2 -14
- data/lib/familia/refinements/time_literals.rb +2 -0
- data/lib/familia/refinements.rb +2 -0
- data/lib/familia/secure_identifier.rb +10 -2
- data/lib/familia/settings.rb +2 -0
- data/lib/familia/thread_safety/instrumented_mutex.rb +166 -0
- data/lib/familia/thread_safety/monitor.rb +328 -0
- data/lib/familia/utils.rb +13 -0
- data/lib/familia/verifiable_identifier.rb +3 -1
- data/lib/familia/version.rb +3 -1
- data/lib/familia.rb +31 -4
- data/lib/middleware/database_command_counter.rb +152 -0
- data/lib/middleware/database_logger.rb +295 -170
- data/lib/multi_result.rb +2 -0
- data/try/edge_cases/empty_identifiers_try.rb +2 -0
- data/try/edge_cases/hash_symbolization_try.rb +2 -0
- data/try/edge_cases/json_serialization_try.rb +2 -0
- data/try/edge_cases/legacy_data_detection/deserialization_edge_cases_try.rb +4 -0
- data/try/edge_cases/race_conditions_try.rb +4 -0
- data/try/edge_cases/reserved_keywords_try.rb +4 -0
- data/try/edge_cases/string_coercion_try.rb +2 -0
- data/try/edge_cases/ttl_side_effects_try.rb +4 -0
- data/try/features/encrypted_fields/aad_protection_try.rb +4 -0
- data/try/features/encrypted_fields/concealed_string_core_try.rb +4 -0
- data/try/features/encrypted_fields/context_isolation_try.rb +4 -0
- data/try/features/encrypted_fields/encrypted_fields_core_try.rb +33 -0
- data/try/features/encrypted_fields/encrypted_fields_integration_try.rb +4 -0
- data/try/features/encrypted_fields/encrypted_fields_no_cache_security_try.rb +4 -0
- data/try/features/encrypted_fields/encrypted_fields_security_try.rb +4 -0
- data/try/features/encrypted_fields/error_conditions_try.rb +4 -0
- data/try/features/encrypted_fields/fresh_key_derivation_try.rb +4 -0
- data/try/features/encrypted_fields/fresh_key_try.rb +4 -0
- data/try/features/encrypted_fields/key_rotation_try.rb +4 -0
- data/try/features/encrypted_fields/memory_security_try.rb +4 -0
- data/try/features/encrypted_fields/missing_current_key_version_try.rb +4 -0
- data/try/features/encrypted_fields/nonce_uniqueness_try.rb +4 -0
- data/try/features/encrypted_fields/secure_by_default_behavior_try.rb +4 -0
- data/try/features/encrypted_fields/thread_safety_try.rb +4 -0
- data/try/features/encrypted_fields/universal_serialization_safety_try.rb +4 -0
- data/try/features/encryption/config_persistence_try.rb +4 -0
- data/try/features/encryption/core_try.rb +4 -0
- data/try/features/encryption/instance_variable_scope_try.rb +4 -0
- data/try/features/encryption/module_loading_try.rb +4 -0
- data/try/features/encryption/providers/aes_gcm_provider_try.rb +4 -0
- data/try/features/encryption/providers/xchacha20_poly1305_provider_try.rb +4 -0
- data/try/features/encryption/roundtrip_validation_try.rb +4 -0
- data/try/features/encryption/secure_memory_handling_try.rb +4 -0
- data/try/features/expiration/expiration_try.rb +4 -0
- data/try/features/external_identifier/external_identifier_try.rb +171 -8
- data/try/features/feature_dependencies_try.rb +2 -0
- data/try/features/feature_improvements_try.rb +2 -0
- data/try/features/field_groups_try.rb +2 -0
- data/try/features/object_identifier/object_identifier_integration_try.rb +12 -9
- data/try/features/object_identifier/object_identifier_try.rb +2 -0
- data/try/features/quantization/quantization_try.rb +4 -0
- data/try/features/real_feature_integration_try.rb +2 -0
- data/try/features/relationships/indexing_commands_verification_try.rb +2 -0
- data/try/features/relationships/indexing_rebuild_try.rb +600 -0
- data/try/features/relationships/indexing_try.rb +2 -0
- data/try/features/relationships/participation_bidirectional_try.rb +242 -0
- data/try/features/relationships/participation_commands_verification_spec.rb +4 -0
- data/try/features/relationships/participation_commands_verification_try.rb +2 -0
- data/try/features/relationships/participation_performance_improvements_try.rb +11 -9
- data/try/features/relationships/participation_reverse_index_try.rb +15 -13
- data/try/features/relationships/participation_target_class_resolution_try.rb +209 -0
- data/try/features/relationships/participation_unresolved_target_try.rb +109 -0
- data/try/features/relationships/relationships_api_changes_try.rb +2 -0
- data/try/features/relationships/relationships_edge_cases_try.rb +4 -0
- data/try/features/relationships/relationships_performance_minimal_try.rb +4 -0
- data/try/features/relationships/relationships_performance_simple_try.rb +4 -0
- data/try/features/relationships/relationships_performance_try.rb +4 -0
- data/try/features/relationships/relationships_performance_working_try.rb +4 -0
- data/try/features/relationships/relationships_try.rb +6 -4
- data/try/features/safe_dump/safe_dump_advanced_try.rb +4 -0
- data/try/features/safe_dump/safe_dump_try.rb +4 -0
- data/try/features/transient_fields/redacted_string_try.rb +2 -0
- data/try/features/transient_fields/refresh_reset_try.rb +3 -0
- data/try/features/transient_fields/simple_refresh_test.rb +3 -0
- data/try/features/transient_fields/single_use_redacted_string_try.rb +2 -0
- data/try/features/transient_fields/transient_fields_core_try.rb +4 -0
- data/try/features/transient_fields/transient_fields_integration_try.rb +4 -0
- data/try/integration/connection/fiber_context_preservation_try.rb +4 -0
- data/try/integration/connection/handler_constraints_try.rb +4 -0
- data/try/integration/connection/isolated_dbclient_try.rb +4 -0
- data/try/integration/connection/middleware_reconnect_try.rb +2 -0
- data/try/integration/connection/operation_mode_guards_try.rb +4 -0
- data/try/integration/connection/pipeline_fallback_integration_try.rb +3 -0
- data/try/integration/connection/pools_try.rb +4 -0
- data/try/integration/connection/responsibility_chain_tracking_try.rb +4 -0
- data/try/integration/connection/transaction_fallback_integration_try.rb +4 -0
- data/try/integration/connection/transaction_mode_permissive_try.rb +4 -0
- data/try/integration/connection/transaction_mode_strict_try.rb +4 -0
- data/try/integration/connection/transaction_mode_warn_try.rb +4 -0
- data/try/integration/connection/transaction_modes_try.rb +4 -0
- data/try/integration/conventional_inheritance_try.rb +4 -0
- data/try/integration/create_method_try.rb +4 -0
- data/try/integration/cross_component_try.rb +4 -0
- data/try/integration/data_types/datatype_pipelines_try.rb +4 -0
- data/try/integration/data_types/datatype_transactions_try.rb +4 -0
- data/try/integration/database_consistency_try.rb +4 -0
- data/try/integration/familia_extended_try.rb +4 -0
- data/try/integration/familia_members_methods_try.rb +4 -0
- data/try/integration/models/customer_safe_dump_try.rb +4 -0
- data/try/integration/models/customer_try.rb +4 -0
- data/try/integration/models/datatype_base_try.rb +4 -0
- data/try/integration/models/familia_object_try.rb +4 -0
- data/try/integration/persistence_operations_try.rb +4 -0
- data/try/integration/relationships_persistence_round_trip_try.rb +17 -14
- data/try/integration/save_methods_consistency_try.rb +241 -0
- data/try/integration/scenarios_try.rb +4 -0
- data/try/integration/secure_identifier_try.rb +4 -0
- data/try/integration/transaction_safety_core_try.rb +176 -0
- data/try/integration/transaction_safety_workflow_try.rb +291 -0
- data/try/integration/verifiable_identifier_try.rb +4 -0
- data/try/investigation/pipeline_routing/README.md +228 -0
- data/try/performance/benchmarks_try.rb +4 -0
- data/try/performance/transaction_safety_benchmark_try.rb +238 -0
- data/try/support/benchmarks/deserialization_benchmark.rb +3 -1
- data/try/support/benchmarks/deserialization_correctness_test.rb +3 -1
- data/try/support/debugging/cache_behavior_tracer.rb +4 -0
- data/try/support/debugging/debug_aad_process.rb +3 -0
- data/try/support/debugging/debug_concealed_internal.rb +3 -0
- data/try/support/debugging/debug_concealed_reveal.rb +3 -0
- data/try/support/debugging/debug_context_aad.rb +3 -0
- data/try/support/debugging/debug_context_simple.rb +3 -0
- data/try/support/debugging/debug_cross_context.rb +3 -0
- data/try/support/debugging/debug_database_load.rb +3 -0
- data/try/support/debugging/debug_encrypted_json_check.rb +3 -0
- data/try/support/debugging/debug_encrypted_json_step_by_step.rb +3 -0
- data/try/support/debugging/debug_exists_lifecycle.rb +3 -0
- data/try/support/debugging/debug_field_decrypt.rb +3 -0
- data/try/support/debugging/debug_fresh_cross_context.rb +3 -0
- data/try/support/debugging/debug_load_path.rb +3 -0
- data/try/support/debugging/debug_method_definition.rb +3 -0
- data/try/support/debugging/debug_method_resolution.rb +3 -0
- data/try/support/debugging/debug_minimal.rb +3 -0
- data/try/support/debugging/debug_provider.rb +3 -0
- data/try/support/debugging/debug_secure_behavior.rb +3 -0
- data/try/support/debugging/debug_string_class.rb +3 -0
- data/try/support/debugging/debug_test.rb +3 -0
- data/try/support/debugging/debug_test_design.rb +3 -0
- data/try/support/debugging/encryption_method_tracer.rb +4 -0
- data/try/support/debugging/provider_diagnostics.rb +4 -0
- data/try/support/helpers/test_cleanup.rb +4 -0
- data/try/support/helpers/test_helpers.rb +5 -0
- data/try/support/memory/memory_basic_test.rb +4 -0
- data/try/support/memory/memory_detailed_test.rb +4 -0
- data/try/support/memory/memory_search_for_string.rb +4 -0
- data/try/support/memory/test_actual_redactedstring_protection.rb +4 -0
- data/try/support/prototypes/atomic_saves_v1_context_proxy.rb +4 -0
- data/try/support/prototypes/atomic_saves_v2_connection_switching.rb +4 -0
- data/try/support/prototypes/atomic_saves_v3_connection_pool.rb +4 -0
- data/try/support/prototypes/atomic_saves_v4.rb +4 -0
- data/try/support/prototypes/lib/atomic_saves_v2_connection_switching_helpers.rb +4 -0
- data/try/support/prototypes/lib/atomic_saves_v3_connection_pool_helpers.rb +4 -0
- data/try/support/prototypes/pooling/configurable_stress_test.rb +4 -0
- data/try/support/prototypes/pooling/lib/atomic_saves_v3_connection_pool_helpers.rb +4 -0
- data/try/support/prototypes/pooling/lib/connection_pool_metrics.rb +4 -0
- data/try/support/prototypes/pooling/lib/connection_pool_stress_test.rb +4 -0
- data/try/support/prototypes/pooling/lib/connection_pool_threading_models.rb +4 -0
- data/try/support/prototypes/pooling/lib/visualize_stress_results.rb +4 -2
- data/try/support/prototypes/pooling/pool_siege.rb +4 -2
- data/try/support/prototypes/pooling/run_stress_tests.rb +4 -2
- data/try/thread_safety/README.md +496 -0
- data/try/thread_safety/class_connection_chain_race_try.rb +265 -0
- data/try/thread_safety/connection_chain_race_try.rb +148 -0
- data/try/thread_safety/encryption_manager_cache_race_try.rb +166 -0
- data/try/thread_safety/feature_registry_race_try.rb +226 -0
- data/try/thread_safety/fiber_pipeline_isolation_try.rb +235 -0
- data/try/thread_safety/fiber_transaction_isolation_try.rb +208 -0
- data/try/thread_safety/field_registration_race_try.rb +222 -0
- data/try/thread_safety/logger_initialization_race_try.rb +170 -0
- data/try/thread_safety/middleware_registration_race_try.rb +154 -0
- data/try/thread_safety/module_config_race_try.rb +175 -0
- data/try/thread_safety/secure_identifier_cache_race_try.rb +226 -0
- data/try/unit/core/autoloader_try.rb +4 -0
- data/try/unit/core/base_enhancements_try.rb +4 -0
- data/try/unit/core/connection_try.rb +4 -0
- data/try/unit/core/errors_try.rb +4 -0
- data/try/unit/core/extensions_try.rb +4 -0
- data/try/unit/core/familia_logger_try.rb +2 -0
- data/try/unit/core/familia_try.rb +4 -0
- data/try/unit/core/middleware_sampling_try.rb +335 -0
- data/try/unit/core/middleware_test_helpers_bug_try.rb +58 -0
- data/try/unit/core/middleware_thread_safety_try.rb +245 -0
- data/try/unit/core/middleware_try.rb +4 -0
- data/try/unit/core/settings_try.rb +4 -0
- data/try/unit/core/time_utils_try.rb +4 -0
- data/try/unit/core/tools_try.rb +4 -0
- data/try/unit/core/utils_try.rb +37 -0
- data/try/unit/data_types/boolean_try.rb +4 -0
- data/try/unit/data_types/counter_try.rb +4 -0
- data/try/unit/data_types/datatype_base_try.rb +4 -0
- data/try/unit/data_types/hash_try.rb +4 -0
- data/try/unit/data_types/list_try.rb +4 -0
- data/try/unit/data_types/lock_try.rb +4 -0
- data/try/unit/data_types/sorted_set_try.rb +4 -0
- data/try/unit/data_types/sorted_set_zadd_options_try.rb +4 -0
- data/try/unit/data_types/string_try.rb +4 -0
- data/try/unit/data_types/unsortedset_try.rb +4 -0
- data/try/unit/familia_resolve_class_try.rb +116 -0
- data/try/unit/horreum/auto_indexing_on_save_try.rb +5 -1
- data/try/unit/horreum/automatic_index_validation_try.rb +2 -0
- data/try/unit/horreum/base_try.rb +4 -0
- data/try/unit/horreum/class_methods_try.rb +4 -0
- data/try/unit/horreum/commands_try.rb +4 -0
- data/try/unit/horreum/defensive_initialization_try.rb +4 -0
- data/try/unit/horreum/destroy_related_fields_cleanup_try.rb +4 -0
- data/try/unit/horreum/enhanced_conflict_handling_try.rb +4 -0
- data/try/unit/horreum/field_categories_try.rb +4 -0
- data/try/unit/horreum/field_definition_try.rb +4 -0
- data/try/unit/horreum/initialization_try.rb +4 -0
- data/try/unit/horreum/json_type_preservation_try.rb +2 -0
- data/try/unit/horreum/optimized_loading_try.rb +156 -0
- data/try/unit/horreum/relations_try.rb +4 -0
- data/try/unit/horreum/serialization_persistent_fields_try.rb +4 -0
- data/try/unit/horreum/serialization_try.rb +4 -0
- data/try/unit/horreum/settings_try.rb +4 -0
- data/try/unit/horreum/unique_index_edge_cases_try.rb +4 -0
- data/try/unit/horreum/unique_index_guard_validation_try.rb +2 -0
- data/try/unit/middleware/database_command_counter_methods_try.rb +139 -0
- data/try/unit/middleware/database_logger_methods_try.rb +251 -0
- data/try/unit/refinements/dear_json_array_methods_try.rb +4 -0
- data/try/unit/refinements/dear_json_hash_methods_try.rb +4 -0
- data/try/unit/refinements/time_literals_numeric_methods_try.rb +4 -0
- data/try/unit/refinements/time_literals_string_methods_try.rb +4 -0
- data/try/unit/thread_safety_monitor_try.rb +149 -0
- metadata +72 -17
- data/.github/workflows/code-quality.yml +0 -138
- data/changelog.d/20251011_012003_delano_159_datatype_transaction_pipeline_support.rst +0 -91
- data/changelog.d/20251011_203905_delano_next.rst +0 -30
- data/changelog.d/20251011_212633_delano_next.rst +0 -13
- data/changelog.d/20251011_221253_delano_next.rst +0 -26
- data/docs/archive/FAMILIA_RELATIONSHIPS.md +0 -210
- data/docs/archive/FAMILIA_TECHNICAL.md +0 -823
- data/docs/archive/FAMILIA_UPDATE.md +0 -226
- data/docs/archive/README.md +0 -64
- data/docs/archive/api-reference.md +0 -333
- data/docs/guides/core-field-system.md +0 -806
- data/docs/guides/implementation.md +0 -276
- 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
|