use std::fs; #[test] fn test_gitignore_protection_env() { let gitignore = fs::read_to_string(".gitignore").expect(".gitignore file not found in project root"); // Check that .env and .pem files are blocked let required_patterns = vec![ ".env", "*.env", "*.env.local", ".env.production", ".env.secret", "*.pem", "!public_key.pem", "*.key", "private_key.pem", "privkey.pem", "ec.key", "chiave_privata.key", ]; for pattern in required_patterns { let has_wildcard = gitignore.contains("*.env.local") || gitignore.contains(".env.local"); let has_env = gitignore.contains("*.env") || gitignore.contains(".env"); let is_env_local = pattern == "*.env.local" || pattern == ".env.local"; if is_env_local { assert!( has_wildcard, ".gitignore must contain pattern '*.env.local' or '.env.local' to protect secrets", ); } else if pattern == ".env.production" || pattern == ".env.secret" || pattern == "*.env" || pattern == ".env" { assert!( has_env, ".gitignore must contain pattern '*.env' or '.env' to protect secrets", ); } else { assert!( gitignore.contains(pattern), ".gitignore must contain pattern '{}' to protect secrets", pattern ); } } println!(".gitignore properly protects .env, .pem, and .key files"); } #[test] fn test_no_private_key_in_git() { let gitignore = match fs::read_to_string(".gitignore") { Ok(c) => c, Err(e) => { println!("WARNING: .gitignore not found: {}", e); return; } }; assert!( gitignore.contains("private_key.pem"), ".gitignore must block private_key.pem" ); assert!( gitignore.contains("privkey.pem"), ".gitignore must block privkey.pem" ); assert!(gitignore.contains("ec.key"), ".gitignore must block ec.key"); assert!( gitignore.contains("chiave_privata.key"), ".gitignore must block chiave_privata.key" ); let output = std::process::Command::new("git") .args(["ls-files", "*.pem", "*.key"]) .output() .expect("Failed to run git ls-files"); let tracked_keys = String::from_utf8(output.stdout).unwrap(); let tracked_keys: Vec<&str> = tracked_keys.lines().collect(); for tracked in tracked_keys.iter().filter(|s| !s.is_empty()) { if !tracked.contains("public_key.pem") { panic!( "Private key file is tracked by git: {}. Remove it with git rm --cached", tracked ); } } println!("PASS: No private keys tracked in git (only public_key.pem allowed)"); } #[test] fn test_no_token_in_source_files() { let mut found_issues = Vec::new(); for entry in fs::read_dir(".").unwrap().filter_map(|e| e.ok()) { let path = entry.path(); if !path.is_file() { continue; } if let Some(ext) = path.extension() && ext == "sh" { let content = fs::read_to_string(&path).unwrap(); for (line_num, line) in content.lines().enumerate() { if line.trim().starts_with('#') || line.to_lowercase().contains("example") || line.to_lowercase().contains("template") { continue; } if line.trim().len() >= 40 { let hex_chars: Vec<_> = line .trim() .chars() .filter(|c| c.is_ascii_hexdigit()) .collect(); if (40..=64).contains(&hex_chars.len()) && (line.to_lowercase().contains("token") || line.to_lowercase().contains("api") || line.to_lowercase().contains("secret")) { found_issues.push(format!( "Potential hardcoded token in {}: line {}: {}", path.display(), line_num + 1, line.trim() )); } } } } } if !found_issues.is_empty() { println!("FAIL: Found potential hardcoded tokens:"); for issue in &found_issues { println!(" {}", issue); } panic!( "Found potential hardcoded tokens in shell scripts: {:?}", found_issues ); } println!("PASS: No hardcoded tokens found in shell scripts"); }