Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/commands/interactive/connection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -819,6 +819,7 @@ Host beta

#[tokio::test]
async fn connect_to_node_resolves_each_alias_auth_policy_before_authentication() {
let _home_lock = crate::test_helpers::EnvGuard::lock_home();
// The shared fallback intentionally carries alpha's policy. The beta
// connection must still stop with beta's BatchMode decision before any
// network connection is attempted.
Expand All @@ -839,6 +840,7 @@ Host beta

#[tokio::test]
async fn connect_to_node_pty_resolves_each_alias_auth_policy_before_authentication() {
let _home_lock = crate::test_helpers::EnvGuard::lock_home();
// Reverse the shared fallback. The alpha PTY path must use alpha's
// PasswordAuthentication policy instead of inheriting beta's BatchMode.
let (command, alpha, beta) = alias_auth_command("beta");
Expand Down Expand Up @@ -886,6 +888,7 @@ Host beta

#[test]
fn interactive_jump_selection_is_cli_then_ssh_config_then_yaml() {
let _home_lock = crate::test_helpers::EnvGuard::lock_home();
let node = Node::new("effective-target".to_string(), 22, "user".to_string())
.with_original_host("target-alias".to_string());
let resolve = |ssh_config: SshConfig, cli_jump: Option<&str>| {
Expand Down Expand Up @@ -937,6 +940,7 @@ Host target-alias

#[test]
fn interactive_jump_chain_keeps_distinct_bastion_and_target_socket_policies() {
let _home_lock = crate::test_helpers::EnvGuard::lock_home();
let ssh_config = SshConfig::parse(
r#"
Host bastion
Expand Down
2 changes: 2 additions & 0 deletions src/commands/interactive/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ mod tests {

#[test]
fn ssh_policy_shell_uses_raw_runner_when_remote_pty_is_disabled() {
let _home_lock = crate::test_helpers::EnvGuard::lock_home();
let cmd = InteractiveCommand {
single_node: true,
multiplex: false,
Expand Down Expand Up @@ -159,6 +160,7 @@ mod tests {

#[test]
fn test_format_prompt() {
let _home_lock = crate::test_helpers::EnvGuard::lock_home();
let cmd = InteractiveCommand {
single_node: false,
multiplex: true,
Expand Down
2 changes: 2 additions & 0 deletions src/commands/network_ping_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ async fn probe_resolves_the_expanded_hostname_not_the_ssh_alias() {

#[tokio::test]
async fn run_expands_cluster_alias_through_ssh_config_hostname() {
let _home_lock = crate::test_helpers::EnvGuard::lock_home();
let address = IpAddr::from([192, 0, 2, 11]);
let mut probe = FakeProbe::default();
probe
Expand Down Expand Up @@ -190,6 +191,7 @@ async fn run_expands_cluster_alias_through_ssh_config_hostname() {

#[tokio::test]
async fn mocked_probe_is_family_aware_and_bounded() {
let _home_lock = crate::test_helpers::EnvGuard::lock_home();
let mut probe = FakeProbe::default();
for index in 1..=4 {
let host = format!("host{index}");
Expand Down
1 change: 1 addition & 0 deletions src/config/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ fn test_expand_tilde() {

#[test]
fn test_config_parsing() {
let _home_lock = crate::test_helpers::EnvGuard::lock_home();
let yaml = r#"
defaults:
user: admin
Expand Down
15 changes: 15 additions & 0 deletions src/executor/connection_manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,7 @@ mod tests {

#[test]
fn command_and_transfer_selection_is_cli_then_ssh_config_then_yaml() {
let _home_lock = crate::test_helpers::EnvGuard::lock_home();
let config_jump = SshConfig::parse(
r#"
Host target-alias
Expand Down Expand Up @@ -383,6 +384,7 @@ Host target-alias

#[test]
fn command_and_transfer_proxy_jump_uses_original_host_alias() {
let _home_lock = crate::test_helpers::EnvGuard::lock_home();
let ssh_config = SshConfig::parse(
r#"
Host target-alias
Expand All @@ -406,6 +408,7 @@ Host effective-target
/// Test that CLI jump hosts take precedence over SSH config
#[test]
fn test_resolve_effective_jump_hosts_cli_precedence() {
let _home_lock = crate::test_helpers::EnvGuard::lock_home();
let ssh_config_content = r#"
Host example.com
ProxyJump bastion.example.com
Expand Down Expand Up @@ -433,6 +436,7 @@ Host example.com
/// Test that SSH config ProxyJump is used when no CLI jump hosts
#[test]
fn test_resolve_effective_jump_hosts_ssh_config_fallback() {
let _home_lock = crate::test_helpers::EnvGuard::lock_home();
let ssh_config_content = r#"
Host example.com
ProxyJump bastion.example.com
Expand All @@ -446,6 +450,7 @@ Host example.com
/// Test that no jump hosts is returned when neither CLI nor SSH config specifies one
#[test]
fn test_resolve_effective_jump_hosts_none() {
let _home_lock = crate::test_helpers::EnvGuard::lock_home();
let ssh_config = SshConfig::new();

let result = resolve_effective_jump_hosts(None, Some(&ssh_config), "example.com");
Expand All @@ -455,13 +460,15 @@ Host example.com
/// Test that no jump hosts is returned when SSH config is not provided
#[test]
fn test_resolve_effective_jump_hosts_no_ssh_config() {
let _home_lock = crate::test_helpers::EnvGuard::lock_home();
let result = resolve_effective_jump_hosts(None, None, "example.com");
assert_eq!(result, None);
}

/// Test multi-hop ProxyJump chain from SSH config
#[test]
fn test_resolve_effective_jump_hosts_multi_hop() {
let _home_lock = crate::test_helpers::EnvGuard::lock_home();
let ssh_config_content = r#"
Host internal.example.com
ProxyJump jump1.example.com,jump2.example.com
Expand All @@ -478,6 +485,7 @@ Host internal.example.com
/// Test ProxyJump with port specification
#[test]
fn test_resolve_effective_jump_hosts_with_port() {
let _home_lock = crate::test_helpers::EnvGuard::lock_home();
let ssh_config_content = r#"
Host internal.example.com
ProxyJump bastion.example.com:2222
Expand All @@ -491,6 +499,7 @@ Host internal.example.com
/// Test ProxyJump with user@host:port format
#[test]
fn test_resolve_effective_jump_hosts_with_user_and_port() {
let _home_lock = crate::test_helpers::EnvGuard::lock_home();
let ssh_config_content = r#"
Host internal.example.com
ProxyJump admin@bastion.example.com:2222
Expand All @@ -504,6 +513,7 @@ Host internal.example.com
/// Test wildcard pattern matching for ProxyJump
#[test]
fn test_resolve_effective_jump_hosts_wildcard() {
let _home_lock = crate::test_helpers::EnvGuard::lock_home();
let ssh_config_content = r#"
Host db.internal.example.com
ProxyJump db-gateway.example.com
Expand All @@ -527,6 +537,7 @@ Host *.internal.example.com
/// Test that unmatched hosts get no ProxyJump
#[test]
fn test_resolve_effective_jump_hosts_no_match() {
let _home_lock = crate::test_helpers::EnvGuard::lock_home();
let ssh_config_content = r#"
Host *.internal.example.com
ProxyJump gateway.example.com
Expand All @@ -540,6 +551,7 @@ Host *.internal.example.com

#[test]
fn direct_proxy_jump_values_normalize_to_an_empty_chain() {
let _home_lock = crate::test_helpers::EnvGuard::lock_home();
for directive in ["none", "direct", "NONE", "DIRECT"] {
let ssh_config_content = format!(
r#"
Expand Down Expand Up @@ -665,6 +677,7 @@ Host *.example.com

#[tokio::test]
async fn command_and_all_transfer_paths_never_dial_proxy_jump_none() {
let _home_lock = crate::test_helpers::EnvGuard::lock_home();
let listener = std::net::TcpListener::bind(("127.0.0.1", 0)).unwrap();
let port = listener.local_addr().unwrap().port();
drop(listener);
Expand Down Expand Up @@ -697,6 +710,7 @@ Host direct-target

#[tokio::test]
async fn all_connection_paths_prefer_config_then_cli_over_yaml() {
let _home_lock = crate::test_helpers::EnvGuard::lock_home();
let ssh_config = SshConfig::parse(
r#"
Host target-alias
Expand Down Expand Up @@ -733,6 +747,7 @@ Host target-alias
/// Test complex multi-hop chain with user and ports
#[test]
fn test_resolve_effective_jump_hosts_complex_chain() {
let _home_lock = crate::test_helpers::EnvGuard::lock_home();
let ssh_config_content = r#"
Host production.internal
ProxyJump user1@jump1.example.com:22,user2@jump2.example.com:2222,jump3.example.com
Expand Down
1 change: 1 addition & 0 deletions src/executor/parallel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2021,6 +2021,7 @@ mod tests {

#[test]
fn connection_config_for_node_resolves_each_node_host_block() {
let _home_lock = crate::test_helpers::EnvGuard::lock_home();
let ssh_config = SshConfig::parse(
r#"
Host v4node
Expand Down
2 changes: 2 additions & 0 deletions src/jump/chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -590,6 +590,7 @@ mod tests {

#[test]
fn test_chain_materializes_jump_alias_endpoint_and_preserves_cli_fields() {
let _home_lock = crate::test_helpers::EnvGuard::lock_home();
let ssh_config = SshConfig::parse(
r#"
Host bastion
Expand Down Expand Up @@ -629,6 +630,7 @@ Host templated

#[test]
fn test_chain_resolves_connection_config_per_jump_host() {
let _home_lock = crate::test_helpers::EnvGuard::lock_home();
let ssh_config = SshConfig::parse(
r#"
Host bastion
Expand Down
1 change: 1 addition & 0 deletions src/jump/chain/auth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ mod tests {
#[tokio::test]
#[serial_test::serial]
async fn test_determine_auth_method_fallback_to_key_file() {
let _home_lock = crate::test_helpers::EnvGuard::lock_home();
// Clear SSH_AUTH_SOCK to ensure agent is "unavailable"; guard restores on drop.
let _sock = EnvGuard::remove("SSH_AUTH_SOCK");

Expand Down
15 changes: 15 additions & 0 deletions src/ssh/auth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -738,6 +738,7 @@ mod tests {

#[test]
fn default_identities_include_the_fido_key_files() {
let _home_lock = crate::test_helpers::EnvGuard::lock_home();
let ctx = AuthContext::new("user".to_string(), "host".to_string()).unwrap();
let names = ctx
.default_key_paths()
Expand Down Expand Up @@ -864,6 +865,7 @@ mod tests {

#[tokio::test]
async fn test_determine_method_with_key_file() {
let _home_lock = crate::test_helpers::EnvGuard::lock_home();
let temp_dir = TempDir::new().unwrap();
let key_path = temp_dir.path().join("test_key");
write_test_key(&key_path);
Expand Down Expand Up @@ -891,6 +893,7 @@ mod tests {

#[tokio::test]
async fn test_timing_attack_mitigation() {
let _home_lock = crate::test_helpers::EnvGuard::lock_home();
let ctx = AuthContext::new("user".to_string(), "host".to_string()).unwrap();

// Measure time for failed authentication
Expand Down Expand Up @@ -1061,6 +1064,7 @@ mod tests {

#[tokio::test]
async fn disabled_and_unpreferred_methods_are_never_planned() {
let _home_lock = crate::test_helpers::EnvGuard::lock_home();
let home = TempDir::new().unwrap();
let key_path = home.path().join("identity");
write_test_key(&key_path);
Expand Down Expand Up @@ -1099,6 +1103,7 @@ mod tests {

#[tokio::test]
async fn batch_mode_never_plans_password_or_passphrase_prompts() {
let _home_lock = crate::test_helpers::EnvGuard::lock_home();
let password_policy = SshAuthenticationPolicy {
preferred_authentications: vec!["password".into()],
pubkey_authentication: false,
Expand Down Expand Up @@ -1156,6 +1161,7 @@ mod tests {

#[tokio::test]
async fn later_invalid_keys_and_password_prompt_stay_lazy_and_ordered() {
let _home_lock = crate::test_helpers::EnvGuard::lock_home();
let home = TempDir::new().unwrap();
let first_key = home.path().join("first-key");
let encrypted_key = home.path().join("encrypted-key");
Expand Down Expand Up @@ -1204,6 +1210,7 @@ mod tests {
}
#[tokio::test]
async fn number_of_password_prompts_is_the_exact_attempt_bound() {
let _home_lock = crate::test_helpers::EnvGuard::lock_home();
let policy = SshAuthenticationPolicy {
preferred_authentications: vec!["password".into()],
pubkey_authentication: false,
Expand All @@ -1222,6 +1229,7 @@ mod tests {

#[tokio::test]
async fn matching_user_certificate_precedes_plain_key() {
let _home_lock = crate::test_helpers::EnvGuard::lock_home();
let home = TempDir::new().unwrap();
let key_path = home.path().join("user-key");
let certificate_path = home.path().join("user-cert.pub");
Expand Down Expand Up @@ -1254,6 +1262,7 @@ mod tests {

#[tokio::test]
async fn automatic_certificate_companion_precedes_plain_identity() {
let _home_lock = crate::test_helpers::EnvGuard::lock_home();
let home = TempDir::new().unwrap();
let key_path = home.path().join("automatic-key");
let certificate_path = AuthContext::automatic_certificate_paths(&key_path)[1].clone();
Expand Down Expand Up @@ -1352,6 +1361,7 @@ mod tests {
#[tokio::test]
#[serial]
async fn explicit_cli_identity_uses_public_companion_when_private_identity_is_offline() {
let _home_lock = crate::test_helpers::EnvGuard::lock_home();
let home = TempDir::new().unwrap();
let _socket = EnvGuard::remove("SSH_AUTH_SOCK");
let private_path = home.path().join("cli-key");
Expand Down Expand Up @@ -1381,6 +1391,7 @@ mod tests {
#[tokio::test]
#[serial]
async fn offline_cli_identity_preserves_base_path_for_automatic_certificate() {
let _home_lock = crate::test_helpers::EnvGuard::lock_home();
let home = TempDir::new().unwrap();
let _socket = EnvGuard::remove("SSH_AUTH_SOCK");
let private_path = home.path().join("cli-key");
Expand Down Expand Up @@ -1455,6 +1466,7 @@ mod tests {
#[tokio::test]
#[serial]
async fn mismatched_local_certificate_remains_a_retryable_agent_candidate() {
let _home_lock = crate::test_helpers::EnvGuard::lock_home();
let home = TempDir::new().unwrap();
let _socket = EnvGuard::remove("SSH_AUTH_SOCK");
let key_path = home.path().join("configured-key");
Expand Down Expand Up @@ -1489,6 +1501,7 @@ mod tests {

#[tokio::test]
async fn missing_and_malformed_cli_identities_leave_later_keys_reachable() {
let _home_lock = crate::test_helpers::EnvGuard::lock_home();
let home = TempDir::new().unwrap();
let missing = home.path().join("missing-key");
let malformed = home.path().join("malformed-key");
Expand Down Expand Up @@ -1519,6 +1532,7 @@ mod tests {
#[tokio::test]
#[serial]
async fn identities_only_public_identity_keeps_matching_agent_certificate_first() {
let _home_lock = crate::test_helpers::EnvGuard::lock_home();
let home = TempDir::new().unwrap();
let private_path = home.path().join("listed-key");
let public_path = home.path().join("listed-key.pub");
Expand Down Expand Up @@ -1555,6 +1569,7 @@ mod tests {

#[tokio::test]
async fn encrypted_rsa_companion_is_filtered_before_any_passphrase_prompt() {
let _home_lock = crate::test_helpers::EnvGuard::lock_home();
let home = TempDir::new().unwrap();
let rsa_path = home.path().join("encrypted-rsa");
crate::keygen::generate_rsa(&rsa_path, 2048, None).unwrap();
Expand Down
2 changes: 2 additions & 0 deletions src/ssh/client/connection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,7 @@ mod tests {

#[test]
fn command_and_transfer_jump_chain_preserves_alias_target_policy() {
let _home_lock = crate::test_helpers::EnvGuard::lock_home();
let ssh_config = SshConfig::parse(
r#"
Host bastion
Expand Down Expand Up @@ -483,6 +484,7 @@ Host effective-target

#[tokio::test]
async fn test_determine_auth_method_with_key() {
let _home_lock = crate::test_helpers::EnvGuard::lock_home();
let temp_dir = TempDir::new().unwrap();
let key_path = temp_dir.path().join("test_key");
write_test_key(&key_path);
Expand Down
Loading
Loading