#![ cfg( feature = "secure" ) ]
use std ::fs;
use workspace_tools :: { testing, SecretInjectable };
use secrecy ::ExposeSecret;
#[ test ]
#[ cfg( feature = "secure" ) ]
fn test_secret_injectable_trait()
{
let ( _temp_dir, workspace ) = testing ::create_test_workspace_with_structure();
let secret_content = "DATABASE_URL=postgresql: //localhost/testdb\nAPI_KEY=secret-key-123";
let secret_file = workspace.secret_file( "-config.sh" );
fs ::write( &secret_file, secret_content ).unwrap();
#[ derive( Debug ) ]
struct AppConfig
{
database_url: String,
api_key: String,
}
impl SecretInjectable for AppConfig
{
fn inject_secret( &mut self, key: &str, value: String ) -> workspace_tools ::Result< () >
{
match key
{
"DATABASE_URL" => self.database_url = value,
"API_KEY" => self.api_key = value,
_ => return Err( workspace_tools ::WorkspaceError ::SecretInjectionError(
format!( "unknown secret key: {key}" )
) ),
}
Ok( () )
}
fn validate_secrets( &self ) -> workspace_tools ::Result< () >
{
if self.api_key.is_empty()
{
return Err( workspace_tools ::WorkspaceError ::SecretValidationError(
"api_key cannot be empty".to_string()
) );
}
Ok( () )
}
}
let initial_config = AppConfig { database_url: String ::new(), api_key: String ::new() };
let config = workspace.load_config_with_secrets( initial_config, "-config.sh" ).unwrap();
assert_eq!( config.database_url, "postgresql: //localhost/testdb" );
assert_eq!( config.api_key, "secret-key-123" );
}
#[ test ]
#[ cfg( feature = "secure" ) ]
fn test_secret_validation()
{
let ( _temp_dir, workspace ) = testing ::create_test_workspace_with_structure();
let weak_secret = workspace.validate_secret( "123" );
assert!( weak_secret.is_err() );
assert!( weak_secret.unwrap_err().to_string().contains( "8 characters" ) );
let common_secret = workspace.validate_secret( "password" );
assert!( common_secret.is_err() );
assert!( common_secret.unwrap_err().to_string().contains( "weak" ) );
let strong_secret = workspace.validate_secret( "super-strong-secret-key-with-entropy-2024!" );
assert!( strong_secret.is_ok() );
}
#[ test ]
#[ cfg( feature = "secure" ) ]
fn test_secure_config_loading()
{
let ( _temp_dir, workspace ) = testing ::create_test_workspace_with_structure();
let config_content = r#"
[database]
url = "${DATABASE_URL}"
password = "${DB_PASSWORD}"
[api]
key = "${API_KEY}"
"#;
let secrets_content = "DATABASE_URL=postgresql: //secure/db\nDB_PASSWORD=secure-password\nAPI_KEY=secure-api-key";
fs ::write( workspace.join( "config.toml" ), config_content ).unwrap();
fs ::write( workspace.secret_file( "-secrets.sh" ), secrets_content ).unwrap();
let injected_config = workspace.load_config_with_secret_injection( "config.toml", "-secrets.sh" ).unwrap();
assert!( injected_config.contains( "postgresql: //secure/db" ) );
assert!( injected_config.contains( "secure-api-key" ) );
assert!( !injected_config.contains( "${" ) ); }
#[ test ]
#[ cfg( feature = "secure" ) ]
fn test_comprehensive_error_handling()
{
let ( _temp_dir, workspace ) = testing ::create_test_workspace_with_structure();
let result = workspace.load_secrets_secure( "nonexistent.sh" );
assert!( result.is_err() ); let error_msg = result.unwrap_err().to_string();
assert!( error_msg.contains( "not found" ) );
let invalid_content = "INVALID FORMAT LINE WITHOUT EQUALS SIGN";
fs ::write( workspace.secret_file( "-invalid.sh" ), invalid_content ).unwrap();
let result = workspace.load_secrets_secure( "-invalid.sh" );
assert!( result.is_ok() ); assert!( result.unwrap().is_empty() );
}
#[ test ]
fn test_zero_overhead_feature_disabled()
{
let ( _temp_dir, workspace ) = testing ::create_test_workspace_with_structure();
let result = workspace.join( "test_path" );
assert!( result.to_string_lossy().ends_with( "test_path" ) );
}
#[ test ]
#[ cfg( feature = "secure" ) ]
fn test_edge_case_handling()
{
let ( _temp_dir, workspace ) = testing ::create_test_workspace_with_structure();
fs ::write( workspace.secret_file( "-empty.sh" ), "" ).unwrap();
let result = workspace.load_secrets_secure( "-empty.sh" );
assert!( result.is_ok() );
assert!( result.unwrap().is_empty() );
fs ::write( workspace.secret_file( "-comments.sh" ), "# Only comments\n# Another comment" ).unwrap();
let result = workspace.load_secrets_secure( "-comments.sh" );
assert!( result.is_ok() );
assert!( result.unwrap().is_empty() );
let long_value = "a".repeat( 10000 );
let long_secret = format!( "LONG_SECRET={long_value}" );
fs ::write( workspace.secret_file( "-long.sh" ), long_secret ).unwrap();
let result = workspace.load_secrets_secure( "-long.sh" );
assert!( result.is_ok() );
let secrets = result.unwrap();
assert_eq!( secrets.get( "LONG_SECRET" ).unwrap().expose_secret(), &long_value );
}
#[ test ]
#[ cfg( feature = "secure" ) ]
fn test_performance_characteristics()
{
let ( _temp_dir, workspace ) = testing ::create_test_workspace_with_structure();
let mut large_content = String ::new();
for i in 0..1000
{
use core ::fmt ::Write;
writeln!( &mut large_content, "SECRET_KEY_{i}=secret-value-{i}" ).unwrap();
}
fs ::write( workspace.secret_file( "-large.sh" ), large_content ).unwrap();
let start = std ::time ::Instant ::now();
let result = workspace.load_secrets_secure( "-large.sh" );
let duration = start.elapsed();
assert!( result.is_ok() );
assert_eq!( result.unwrap().len(), 1000 );
assert!( duration.as_millis() < 100 );
}
#[ test ]
#[ cfg( feature = "secure" ) ]
fn test_security_best_practices()
{
let ( _temp_dir, workspace ) = testing ::create_test_workspace_with_structure();
{
let secret_content = "TEMP_SECRET=temporary-value";
fs ::write( workspace.secret_file( "-temp.sh" ), secret_content ).unwrap();
let secrets = workspace.load_secrets_secure( "-temp.sh" ).unwrap();
let temp_secret = secrets.get( "TEMP_SECRET" ).unwrap().clone();
assert_eq!( temp_secret.expose_secret(), "temporary-value" );
}
let secret_content = "DEBUG_SECRET=should-not-appear-in-debug";
fs ::write( workspace.secret_file( "-debug.sh" ), secret_content ).unwrap();
let secrets = workspace.load_secrets_secure( "-debug.sh" ).unwrap();
let debug_output = format!( "{secrets:?}" );
assert!( !debug_output.contains( "should-not-appear-in-debug" ) );
assert!( debug_output.contains( "Secret" ) || debug_output.contains( "[REDACTED]" ) || debug_output.contains( "***" ) );
}