1
+ //! Basic encryption tests that don't require database access
2
+ //!
3
+ //! These tests validate the core encryption functionality without requiring
4
+ //! external database connections, making them suitable for CI/CD environments.
5
+
6
+ use hammerwork:: encryption:: {
7
+ EncryptionAlgorithm , EncryptionKey , KeyManagerConfig , KeyOperation , KeyPurpose , KeySource ,
8
+ KeyStatus , parse_algorithm, parse_key_source, parse_key_purpose, parse_key_status,
9
+ ExternalKmsConfig , KeyDerivationConfig , KeyManagerStats ,
10
+ } ;
11
+ use chrono:: { Duration , Utc } ;
12
+ use std:: collections:: HashMap ;
13
+ use std:: env;
14
+ use uuid:: Uuid ;
15
+
16
+ // Helper function to create test key manager configuration
17
+ fn create_test_config ( ) -> KeyManagerConfig {
18
+ KeyManagerConfig :: new ( )
19
+ . with_master_key_env ( "TEST_MASTER_KEY" )
20
+ . with_auto_rotation_enabled ( true )
21
+ . with_rotation_interval ( Duration :: days ( 30 ) )
22
+ . with_max_key_versions ( 5 )
23
+ . with_audit_enabled ( true )
24
+ }
25
+
26
+ // Helper function to create test encryption key
27
+ fn create_test_encryption_key ( key_id : & str ) -> EncryptionKey {
28
+ EncryptionKey {
29
+ id : Uuid :: new_v4 ( ) ,
30
+ key_id : key_id. to_string ( ) ,
31
+ version : 1 ,
32
+ algorithm : EncryptionAlgorithm :: AES256GCM ,
33
+ encrypted_key_material : vec ! [ 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 ] , // Mock encrypted data
34
+ derivation_salt : Some ( vec ! [ 9 , 10 , 11 , 12 ] ) ,
35
+ source : KeySource :: Generated ( "test" . to_string ( ) ) ,
36
+ purpose : KeyPurpose :: Encryption ,
37
+ created_at : Utc :: now ( ) ,
38
+ created_by : Some ( "test-user" . to_string ( ) ) ,
39
+ expires_at : Some ( Utc :: now ( ) + Duration :: days ( 365 ) ) ,
40
+ rotated_at : None ,
41
+ retired_at : None ,
42
+ status : KeyStatus :: Active ,
43
+ rotation_interval : Some ( Duration :: days ( 90 ) ) ,
44
+ next_rotation_at : Some ( Utc :: now ( ) + Duration :: days ( 90 ) ) ,
45
+ key_strength : 256 ,
46
+ master_key_id : Some ( Uuid :: new_v4 ( ) ) ,
47
+ last_used_at : None ,
48
+ usage_count : 0 ,
49
+ }
50
+ }
51
+
52
+ #[ cfg( test) ]
53
+ mod unit_tests {
54
+ use super :: * ;
55
+
56
+ #[ test]
57
+ fn test_key_manager_config_creation ( ) {
58
+ let config = create_test_config ( ) ;
59
+
60
+ assert_eq ! (
61
+ config. master_key_source,
62
+ KeySource :: Environment ( "TEST_MASTER_KEY" . to_string( ) )
63
+ ) ;
64
+ assert ! ( config. auto_rotation_enabled) ;
65
+ assert_eq ! ( config. default_rotation_interval, Duration :: days( 30 ) ) ;
66
+ assert_eq ! ( config. max_key_versions, 5 ) ;
67
+ assert ! ( config. audit_enabled) ;
68
+ }
69
+
70
+ #[ test]
71
+ fn test_key_manager_config_builder_pattern ( ) {
72
+ let config = KeyManagerConfig :: new ( )
73
+ . with_master_key_env ( "CUSTOM_MASTER_KEY" )
74
+ . with_auto_rotation_enabled ( false )
75
+ . with_rotation_interval ( Duration :: days ( 60 ) )
76
+ . with_max_key_versions ( 3 )
77
+ . with_audit_enabled ( false ) ;
78
+
79
+ assert_eq ! (
80
+ config. master_key_source,
81
+ KeySource :: Environment ( "CUSTOM_MASTER_KEY" . to_string( ) )
82
+ ) ;
83
+ assert ! ( !config. auto_rotation_enabled) ;
84
+ assert_eq ! ( config. default_rotation_interval, Duration :: days( 60 ) ) ;
85
+ assert_eq ! ( config. max_key_versions, 3 ) ;
86
+ assert ! ( !config. audit_enabled) ;
87
+ }
88
+
89
+ #[ test]
90
+ fn test_encryption_key_creation ( ) {
91
+ let key = create_test_encryption_key ( "test-key-1" ) ;
92
+
93
+ assert_eq ! ( key. key_id, "test-key-1" ) ;
94
+ assert_eq ! ( key. version, 1 ) ;
95
+ assert_eq ! ( key. algorithm, EncryptionAlgorithm :: AES256GCM ) ;
96
+ assert_eq ! ( key. purpose, KeyPurpose :: Encryption ) ;
97
+ assert_eq ! ( key. status, KeyStatus :: Active ) ;
98
+ assert_eq ! ( key. key_strength, 256 ) ;
99
+ assert_eq ! ( key. usage_count, 0 ) ;
100
+ assert ! ( key. expires_at. is_some( ) ) ;
101
+ assert ! ( key. rotation_interval. is_some( ) ) ;
102
+ assert ! ( key. next_rotation_at. is_some( ) ) ;
103
+ }
104
+
105
+ #[ test]
106
+ fn test_key_purpose_serialization ( ) {
107
+ let purposes = vec ! [
108
+ KeyPurpose :: Encryption ,
109
+ KeyPurpose :: MAC ,
110
+ KeyPurpose :: KEK ,
111
+ ] ;
112
+
113
+ for purpose in purposes {
114
+ let serialized = serde_json:: to_string ( & purpose) . unwrap ( ) ;
115
+ let deserialized: KeyPurpose = serde_json:: from_str ( & serialized) . unwrap ( ) ;
116
+ assert_eq ! ( purpose, deserialized) ;
117
+ }
118
+ }
119
+
120
+ #[ test]
121
+ fn test_key_status_serialization ( ) {
122
+ let statuses = vec ! [
123
+ KeyStatus :: Active ,
124
+ KeyStatus :: Retired ,
125
+ KeyStatus :: Revoked ,
126
+ KeyStatus :: Expired ,
127
+ ] ;
128
+
129
+ for status in statuses {
130
+ let serialized = serde_json:: to_string ( & status) . unwrap ( ) ;
131
+ let deserialized: KeyStatus = serde_json:: from_str ( & serialized) . unwrap ( ) ;
132
+ assert_eq ! ( status, deserialized) ;
133
+ }
134
+ }
135
+
136
+ #[ test]
137
+ fn test_external_kms_config ( ) {
138
+ let mut auth_config = HashMap :: new ( ) ;
139
+ auth_config. insert ( "access_key_id" . to_string ( ) , "test_access_key" . to_string ( ) ) ;
140
+ auth_config. insert ( "secret_access_key" . to_string ( ) , "test_secret_key" . to_string ( ) ) ;
141
+
142
+ let kms_config = ExternalKmsConfig {
143
+ service_type : "AWS" . to_string ( ) ,
144
+ endpoint : "https://kms.us-east-1.amazonaws.com" . to_string ( ) ,
145
+ auth_config,
146
+ region : Some ( "us-east-1" . to_string ( ) ) ,
147
+ namespace : Some ( "hammerwork-test" . to_string ( ) ) ,
148
+ } ;
149
+
150
+ assert_eq ! ( kms_config. service_type, "AWS" ) ;
151
+ assert_eq ! ( kms_config. endpoint, "https://kms.us-east-1.amazonaws.com" ) ;
152
+ assert ! ( kms_config. auth_config. contains_key( "access_key_id" ) ) ;
153
+ assert ! ( kms_config. auth_config. contains_key( "secret_access_key" ) ) ;
154
+ assert_eq ! ( kms_config. region, Some ( "us-east-1" . to_string( ) ) ) ;
155
+ assert_eq ! ( kms_config. namespace, Some ( "hammerwork-test" . to_string( ) ) ) ;
156
+ }
157
+
158
+ #[ test]
159
+ fn test_key_derivation_config_defaults ( ) {
160
+ let config = KeyDerivationConfig :: default ( ) ;
161
+
162
+ assert_eq ! ( config. memory_cost, 65536 ) ; // 64 MB
163
+ assert_eq ! ( config. time_cost, 3 ) ;
164
+ assert_eq ! ( config. parallelism, 4 ) ;
165
+ assert_eq ! ( config. salt_length, 32 ) ;
166
+ }
167
+ }
168
+
169
+ #[ cfg( test) ]
170
+ mod parsing_tests {
171
+ use super :: * ;
172
+
173
+ #[ test]
174
+ fn test_valid_key_source_parsing ( ) {
175
+ let valid_sources = vec ! [
176
+ ( "Environment(TEST_KEY)" , KeySource :: Environment ( "TEST_KEY" . to_string( ) ) ) ,
177
+ ( "Static(secret_key)" , KeySource :: Static ( "secret_key" . to_string( ) ) ) ,
178
+ ( "Generated(random)" , KeySource :: Generated ( "random" . to_string( ) ) ) ,
179
+ ( "External(aws_kms_key)" , KeySource :: External ( "aws_kms_key" . to_string( ) ) ) ,
180
+ ] ;
181
+
182
+ for ( source_str, expected) in valid_sources {
183
+ let result = parse_key_source ( source_str) ;
184
+ assert ! ( result. is_ok( ) , "Failed to parse valid source: {}" , source_str) ;
185
+ assert_eq ! ( result. unwrap( ) , expected) ;
186
+ }
187
+ }
188
+
189
+ #[ test]
190
+ fn test_invalid_key_source_parsing ( ) {
191
+ let invalid_sources = vec ! [
192
+ "InvalidType(test)" ,
193
+ "Environment" , // Missing parentheses
194
+ "Static(" , // Missing closing parenthesis
195
+ "" , // Empty string
196
+ ] ;
197
+
198
+ for invalid_source in invalid_sources {
199
+ let result = parse_key_source ( invalid_source) ;
200
+ assert ! ( result. is_err( ) , "Expected error for invalid source: {}" , invalid_source) ;
201
+ }
202
+ }
203
+
204
+ #[ test]
205
+ fn test_valid_algorithm_parsing ( ) {
206
+ let valid_algorithms = vec ! [
207
+ ( "AES256GCM" , EncryptionAlgorithm :: AES256GCM ) ,
208
+ ( "ChaCha20Poly1305" , EncryptionAlgorithm :: ChaCha20Poly1305 ) ,
209
+ ] ;
210
+
211
+ for ( algo_str, expected) in valid_algorithms {
212
+ let result = parse_algorithm ( algo_str) ;
213
+ assert ! ( result. is_ok( ) , "Failed to parse valid algorithm: {}" , algo_str) ;
214
+ assert_eq ! ( result. unwrap( ) , expected) ;
215
+ }
216
+ }
217
+
218
+ #[ test]
219
+ fn test_invalid_algorithm_parsing ( ) {
220
+ let invalid_algorithms = vec ! [
221
+ "InvalidAlgorithm" ,
222
+ "AES128" ,
223
+ "RSA2048" ,
224
+ "" ,
225
+ ] ;
226
+
227
+ for invalid_algorithm in invalid_algorithms {
228
+ let result = parse_algorithm ( invalid_algorithm) ;
229
+ assert ! ( result. is_err( ) , "Expected error for invalid algorithm: {}" , invalid_algorithm) ;
230
+ }
231
+ }
232
+
233
+ #[ test]
234
+ fn test_key_manager_stats_default ( ) {
235
+ let stats = KeyManagerStats :: default ( ) ;
236
+
237
+ assert_eq ! ( stats. total_keys, 0 ) ;
238
+ assert_eq ! ( stats. active_keys, 0 ) ;
239
+ assert_eq ! ( stats. retired_keys, 0 ) ;
240
+ assert_eq ! ( stats. revoked_keys, 0 ) ;
241
+ assert_eq ! ( stats. expired_keys, 0 ) ;
242
+ assert_eq ! ( stats. total_access_operations, 0 ) ;
243
+ assert_eq ! ( stats. rotations_performed, 0 ) ;
244
+ assert_eq ! ( stats. average_key_age_days, 0.0 ) ;
245
+ assert_eq ! ( stats. keys_expiring_soon, 0 ) ;
246
+ assert_eq ! ( stats. keys_due_for_rotation, 0 ) ;
247
+ }
248
+ }
0 commit comments