familia 2.0.0.pre4 → 2.0.0.pre6

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 (178) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +3 -0
  3. data/.rubocop_todo.yml +17 -17
  4. data/CLAUDE.md +11 -8
  5. data/Gemfile +5 -1
  6. data/Gemfile.lock +19 -3
  7. data/README.md +36 -157
  8. data/docs/overview.md +359 -0
  9. data/docs/wiki/API-Reference.md +347 -0
  10. data/docs/wiki/Connection-Pooling-Guide.md +437 -0
  11. data/docs/wiki/Encrypted-Fields-Overview.md +101 -0
  12. data/docs/wiki/Expiration-Feature-Guide.md +596 -0
  13. data/docs/wiki/Feature-System-Guide.md +600 -0
  14. data/docs/wiki/Features-System-Developer-Guide.md +892 -0
  15. data/docs/wiki/Field-System-Guide.md +784 -0
  16. data/docs/wiki/Home.md +106 -0
  17. data/docs/wiki/Implementation-Guide.md +276 -0
  18. data/docs/wiki/Quantization-Feature-Guide.md +721 -0
  19. data/docs/wiki/RelatableObjects-Guide.md +563 -0
  20. data/docs/wiki/Security-Model.md +183 -0
  21. data/docs/wiki/Transient-Fields-Guide.md +280 -0
  22. data/lib/familia/base.rb +18 -27
  23. data/lib/familia/connection.rb +6 -5
  24. data/lib/familia/{datatype → data_type}/commands.rb +2 -5
  25. data/lib/familia/{datatype → data_type}/serialization.rb +8 -10
  26. data/lib/familia/data_type/types/counter.rb +38 -0
  27. data/lib/familia/{datatype → data_type}/types/hashkey.rb +20 -2
  28. data/lib/familia/{datatype → data_type}/types/list.rb +17 -18
  29. data/lib/familia/data_type/types/lock.rb +43 -0
  30. data/lib/familia/{datatype → data_type}/types/sorted_set.rb +17 -17
  31. data/lib/familia/{datatype → data_type}/types/string.rb +11 -3
  32. data/lib/familia/{datatype → data_type}/types/unsorted_set.rb +17 -18
  33. data/lib/familia/{datatype.rb → data_type.rb} +12 -14
  34. data/lib/familia/encryption/encrypted_data.rb +137 -0
  35. data/lib/familia/encryption/manager.rb +119 -0
  36. data/lib/familia/encryption/provider.rb +49 -0
  37. data/lib/familia/encryption/providers/aes_gcm_provider.rb +123 -0
  38. data/lib/familia/encryption/providers/secure_xchacha20_poly1305_provider.rb +184 -0
  39. data/lib/familia/encryption/providers/xchacha20_poly1305_provider.rb +138 -0
  40. data/lib/familia/encryption/registry.rb +50 -0
  41. data/lib/familia/encryption.rb +178 -0
  42. data/lib/familia/encryption_request_cache.rb +68 -0
  43. data/lib/familia/errors.rb +17 -3
  44. data/lib/familia/features/encrypted_fields/concealed_string.rb +295 -0
  45. data/lib/familia/features/encrypted_fields/encrypted_field_type.rb +221 -0
  46. data/lib/familia/features/encrypted_fields.rb +28 -0
  47. data/lib/familia/features/expiration.rb +107 -77
  48. data/lib/familia/features/quantization.rb +5 -9
  49. data/lib/familia/features/relatable_objects.rb +2 -4
  50. data/lib/familia/features/safe_dump.rb +14 -17
  51. data/lib/familia/features/transient_fields/redacted_string.rb +159 -0
  52. data/lib/familia/features/transient_fields/single_use_redacted_string.rb +62 -0
  53. data/lib/familia/features/transient_fields/transient_field_type.rb +139 -0
  54. data/lib/familia/features/transient_fields.rb +47 -0
  55. data/lib/familia/features.rb +40 -24
  56. data/lib/familia/field_type.rb +273 -0
  57. data/lib/familia/horreum/{connection.rb → core/connection.rb} +6 -15
  58. data/lib/familia/horreum/{commands.rb → core/database_commands.rb} +20 -21
  59. data/lib/familia/horreum/core/serialization.rb +535 -0
  60. data/lib/familia/horreum/{utils.rb → core/utils.rb} +9 -12
  61. data/lib/familia/horreum/core.rb +21 -0
  62. data/lib/familia/horreum/{settings.rb → shared/settings.rb} +10 -4
  63. data/lib/familia/horreum/subclass/definition.rb +469 -0
  64. data/lib/familia/horreum/{class_methods.rb → subclass/management.rb} +27 -250
  65. data/lib/familia/horreum/{related_fields_management.rb → subclass/related_fields_management.rb} +15 -10
  66. data/lib/familia/horreum.rb +30 -22
  67. data/lib/familia/logging.rb +14 -14
  68. data/lib/familia/settings.rb +39 -3
  69. data/lib/familia/utils.rb +45 -0
  70. data/lib/familia/version.rb +1 -1
  71. data/lib/familia.rb +3 -2
  72. data/try/core/base_enhancements_try.rb +115 -0
  73. data/try/core/connection_try.rb +0 -1
  74. data/try/core/create_method_try.rb +240 -0
  75. data/try/core/database_consistency_try.rb +299 -0
  76. data/try/core/errors_try.rb +25 -5
  77. data/try/core/familia_extended_try.rb +3 -4
  78. data/try/core/familia_try.rb +1 -2
  79. data/try/core/persistence_operations_try.rb +297 -0
  80. data/try/core/pools_try.rb +2 -2
  81. data/try/core/secure_identifier_try.rb +0 -1
  82. data/try/core/settings_try.rb +0 -1
  83. data/try/core/utils_try.rb +0 -1
  84. data/try/{datatypes → data_types}/boolean_try.rb +1 -2
  85. data/try/data_types/counter_try.rb +93 -0
  86. data/try/{datatypes → data_types}/datatype_base_try.rb +2 -3
  87. data/try/{datatypes → data_types}/hash_try.rb +1 -2
  88. data/try/{datatypes → data_types}/list_try.rb +1 -2
  89. data/try/data_types/lock_try.rb +133 -0
  90. data/try/{datatypes → data_types}/set_try.rb +1 -2
  91. data/try/{datatypes → data_types}/sorted_set_try.rb +1 -2
  92. data/try/{datatypes → data_types}/string_try.rb +1 -2
  93. data/try/debugging/README.md +32 -0
  94. data/try/debugging/cache_behavior_tracer.rb +91 -0
  95. data/try/debugging/debug_aad_process.rb +82 -0
  96. data/try/debugging/debug_concealed_internal.rb +59 -0
  97. data/try/debugging/debug_concealed_reveal.rb +61 -0
  98. data/try/debugging/debug_context_aad.rb +68 -0
  99. data/try/debugging/debug_context_simple.rb +80 -0
  100. data/try/debugging/debug_cross_context.rb +62 -0
  101. data/try/debugging/debug_database_load.rb +64 -0
  102. data/try/debugging/debug_encrypted_json_check.rb +53 -0
  103. data/try/debugging/debug_encrypted_json_step_by_step.rb +62 -0
  104. data/try/debugging/debug_exists_lifecycle.rb +54 -0
  105. data/try/debugging/debug_field_decrypt.rb +74 -0
  106. data/try/debugging/debug_fresh_cross_context.rb +73 -0
  107. data/try/debugging/debug_load_path.rb +66 -0
  108. data/try/debugging/debug_method_definition.rb +46 -0
  109. data/try/debugging/debug_method_resolution.rb +41 -0
  110. data/try/debugging/debug_minimal.rb +24 -0
  111. data/try/debugging/debug_provider.rb +68 -0
  112. data/try/debugging/debug_secure_behavior.rb +73 -0
  113. data/try/debugging/debug_string_class.rb +46 -0
  114. data/try/debugging/debug_test.rb +46 -0
  115. data/try/debugging/debug_test_design.rb +80 -0
  116. data/try/debugging/encryption_method_tracer.rb +138 -0
  117. data/try/debugging/provider_diagnostics.rb +110 -0
  118. data/try/edge_cases/hash_symbolization_try.rb +0 -1
  119. data/try/edge_cases/json_serialization_try.rb +0 -1
  120. data/try/edge_cases/reserved_keywords_try.rb +42 -11
  121. data/try/encryption/config_persistence_try.rb +192 -0
  122. data/try/encryption/encryption_core_try.rb +328 -0
  123. data/try/encryption/instance_variable_scope_try.rb +31 -0
  124. data/try/encryption/module_loading_try.rb +28 -0
  125. data/try/encryption/providers/aes_gcm_provider_try.rb +178 -0
  126. data/try/encryption/providers/xchacha20_poly1305_provider_try.rb +169 -0
  127. data/try/encryption/roundtrip_validation_try.rb +28 -0
  128. data/try/encryption/secure_memory_handling_try.rb +125 -0
  129. data/try/features/encrypted_fields_core_try.rb +125 -0
  130. data/try/features/encrypted_fields_integration_try.rb +216 -0
  131. data/try/features/encrypted_fields_no_cache_security_try.rb +219 -0
  132. data/try/features/encrypted_fields_security_try.rb +377 -0
  133. data/try/features/encryption_fields/aad_protection_try.rb +138 -0
  134. data/try/features/encryption_fields/concealed_string_core_try.rb +250 -0
  135. data/try/features/encryption_fields/context_isolation_try.rb +141 -0
  136. data/try/features/encryption_fields/error_conditions_try.rb +116 -0
  137. data/try/features/encryption_fields/fresh_key_derivation_try.rb +128 -0
  138. data/try/features/encryption_fields/fresh_key_try.rb +168 -0
  139. data/try/features/encryption_fields/key_rotation_try.rb +123 -0
  140. data/try/features/encryption_fields/memory_security_try.rb +37 -0
  141. data/try/features/encryption_fields/missing_current_key_version_try.rb +23 -0
  142. data/try/features/encryption_fields/nonce_uniqueness_try.rb +56 -0
  143. data/try/features/encryption_fields/secure_by_default_behavior_try.rb +310 -0
  144. data/try/features/encryption_fields/thread_safety_try.rb +199 -0
  145. data/try/features/encryption_fields/universal_serialization_safety_try.rb +174 -0
  146. data/try/features/expiration_try.rb +0 -1
  147. data/try/features/feature_dependencies_try.rb +159 -0
  148. data/try/features/quantization_try.rb +0 -1
  149. data/try/features/real_feature_integration_try.rb +148 -0
  150. data/try/features/relatable_objects_try.rb +0 -1
  151. data/try/features/safe_dump_advanced_try.rb +0 -1
  152. data/try/features/safe_dump_try.rb +0 -1
  153. data/try/features/transient_fields/redacted_string_try.rb +248 -0
  154. data/try/features/transient_fields/refresh_reset_try.rb +164 -0
  155. data/try/features/transient_fields/simple_refresh_test.rb +50 -0
  156. data/try/features/transient_fields/single_use_redacted_string_try.rb +310 -0
  157. data/try/features/transient_fields_core_try.rb +181 -0
  158. data/try/features/transient_fields_integration_try.rb +260 -0
  159. data/try/helpers/test_helpers.rb +67 -0
  160. data/try/horreum/base_try.rb +157 -3
  161. data/try/horreum/enhanced_conflict_handling_try.rb +176 -0
  162. data/try/horreum/field_categories_try.rb +118 -0
  163. data/try/horreum/field_definition_try.rb +96 -0
  164. data/try/horreum/initialization_try.rb +1 -2
  165. data/try/horreum/relations_try.rb +1 -2
  166. data/try/horreum/serialization_persistent_fields_try.rb +165 -0
  167. data/try/horreum/serialization_try.rb +41 -7
  168. data/try/memory/memory_basic_test.rb +73 -0
  169. data/try/memory/memory_detailed_test.rb +121 -0
  170. data/try/memory/memory_docker_ruby_dump.sh +80 -0
  171. data/try/memory/memory_search_for_string.rb +83 -0
  172. data/try/memory/test_actual_redactedstring_protection.rb +38 -0
  173. data/try/models/customer_safe_dump_try.rb +1 -2
  174. data/try/models/customer_try.rb +1 -2
  175. data/try/models/datatype_base_try.rb +1 -2
  176. data/try/models/familia_object_try.rb +0 -1
  177. metadata +131 -23
  178. data/lib/familia/horreum/serialization.rb +0 -445
data/docs/wiki/Home.md ADDED
@@ -0,0 +1,106 @@
1
+ # Familia v2.0 Documentation
2
+
3
+ Welcome to the comprehensive documentation for Familia v2.0. This wiki covers all major features including security, connection management, architecture, and object relationships.
4
+
5
+ ## 📚 Documentation Structure
6
+
7
+ ### 🔐 Security & Data Protection
8
+
9
+ 1. **[Encrypted Fields Overview](Encrypted-Fields-Overview.md)** - Persistent encrypted storage with modular providers
10
+ 2. **[Transient Fields Guide](Transient-Fields-Guide.md)** - Non-persistent secure data handling with RedactedString
11
+ 3. **[Security Model](Security-Model.md)** - Cryptographic design and Ruby memory limitations
12
+
13
+ ### 🏗️ Architecture & System Design
14
+
15
+ 4. **[Feature System Guide](Feature-System-Guide.md)** - Modular architecture with dependencies and conflict resolution _(new!)_
16
+ 5. **[Connection Pooling Guide](Connection-Pooling-Guide.md)** - Provider pattern for efficient Redis/Valkey pooling _(new!)_
17
+ 6. **[RelatableObjects Guide](RelatableObjects-Guide.md)** - Object relationships and ownership system _(new!)_
18
+
19
+ ### 🛠️ Implementation & Usage
20
+
21
+ 7. **[Implementation Guide](Implementation-Guide.md)** - Configuration, providers, and advanced usage
22
+ 8. **[API Reference](API-Reference.md)** - Complete class and method documentation
23
+
24
+ ### 🚀 Operations (As Needed)
25
+
26
+ 9. **[Migration Guide](Migration-Guide.md)** - Upgrading existing fields _(coming soon)_
27
+ 10. **[Key Management](Key-Management.md)** - Rotation and best practices _(coming soon)_
28
+
29
+ ## 🚀 Quick Start Examples
30
+
31
+ ### Encrypted Fields (Persistent)
32
+ ```ruby
33
+ class User < Familia::Horreum
34
+ feature :encrypted_fields
35
+ encrypted_field :secret_recipe
36
+ end
37
+
38
+ # Configure encryption
39
+ Familia.configure do |config|
40
+ config.encryption_keys = { v1: ENV['FAMILIA_ENCRYPTION_KEY'] }
41
+ config.current_key_version = :v1
42
+ end
43
+
44
+ user = User.new(secret_recipe: "donna's cookies")
45
+ user.save
46
+ user.secret_recipe # => "donna's cookies" (automatically decrypted)
47
+ ```
48
+
49
+ ### Feature System (Modular)
50
+ ```ruby
51
+ class Customer < Familia::Horreum
52
+ feature :safe_dump # API-safe serialization
53
+ feature :expiration # TTL support
54
+ feature :encrypted_fields # Secure storage
55
+
56
+ field :name, :email
57
+ encrypted_field :api_key
58
+ default_expiration 24.hours
59
+ safe_dump_fields :name, :email
60
+ end
61
+ ```
62
+
63
+ ### Connection Pooling (Performance)
64
+ ```ruby
65
+ # Configure connection provider for multi-database pooling
66
+ Familia.connection_provider = lambda do |uri|
67
+ parsed = URI.parse(uri)
68
+ pool_key = "#{parsed.host}:#{parsed.port}/#{parsed.db || 0}"
69
+
70
+ @pools[pool_key] ||= ConnectionPool.new(size: 10) do
71
+ Redis.new(host: parsed.host, port: parsed.port, db: parsed.db || 0)
72
+ end
73
+
74
+ @pools[pool_key].with { |conn| conn }
75
+ end
76
+ ```
77
+
78
+ ### Object Relationships (RelatableObjects)
79
+ ```ruby
80
+ class Customer < Familia::Horreum
81
+ feature :relatable_object
82
+ self.logical_database = 0
83
+ field :name, :email
84
+ end
85
+
86
+ class Domain < Familia::Horreum
87
+ feature :relatable_object
88
+ self.logical_database = 0
89
+ field :name, :dns_zone
90
+ end
91
+
92
+ # Create objects with automatic ID generation
93
+ customer = Customer.new(name: "Acme Corp")
94
+ domain = Domain.new(name: "acme.com")
95
+
96
+ # Establish ownership
97
+ Customer.owners.set(domain.objid, customer.objid)
98
+ domain.owner?(customer) # => true
99
+ ```
100
+
101
+
102
+ ## Related Resources
103
+
104
+ - [Familia README](https://github.com/delano/familia) - Main project documentation
105
+ - [Issue #57](https://github.com/delano/familia/issues/57) - Original feature proposal
106
+ - [Issue #58](https://github.com/delano/familia/issues/58) - Wiki documentation tracking
@@ -0,0 +1,276 @@
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 → Redis/Valkey
9
+ Redis/Valkey → 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.rediskey, "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
+ - [Migration Guide](Migration-Guide) - Upgrade existing fields