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