Skip to content

Commit c6bf1e5

Browse files
committed
test: [#428] harden SSH test key permissions and print execute errors
1 parent 6453494 commit c6bf1e5

1 file changed

Lines changed: 33 additions & 3 deletions

File tree

tests/ssh_client/mod.rs

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ pub mod configuration_tests;
99
pub mod connectivity_tests;
1010

1111
// Re-export common SSH testing utilities
12+
use std::fs;
1213
use std::net::{IpAddr, SocketAddr};
1314
use std::path::PathBuf;
1415
use std::time::{Duration, Instant};
@@ -105,9 +106,16 @@ impl SshTestBuilder {
105106

106107
/// Build the SSH client with configured parameters
107108
pub fn build_client(self) -> SshClient {
109+
let private_key_path = self.private_key_path.unwrap();
110+
let public_key_path = self.public_key_path.unwrap();
111+
112+
// CI runners may check out fixture keys with permissive file modes.
113+
// OpenSSH rejects private keys that are readable by group/others.
114+
normalize_private_key_permissions(&private_key_path);
115+
108116
let ssh_credentials = SshCredentials::new(
109-
self.private_key_path.unwrap(),
110-
self.public_key_path.unwrap(),
117+
private_key_path,
118+
public_key_path,
111119
Username::new(self.username.unwrap()).unwrap(),
112120
);
113121

@@ -126,6 +134,26 @@ impl Default for SshTestBuilder {
126134
}
127135
}
128136

137+
#[cfg(unix)]
138+
fn normalize_private_key_permissions(private_key_path: &std::path::Path) {
139+
use std::os::unix::fs::PermissionsExt;
140+
141+
if private_key_path.exists() {
142+
let mode_600 = fs::Permissions::from_mode(0o600);
143+
if let Err(error) = fs::set_permissions(private_key_path, mode_600) {
144+
eprintln!(
145+
"Warning: failed to enforce 0600 permissions on {}: {error}",
146+
private_key_path.display()
147+
);
148+
}
149+
}
150+
}
151+
152+
#[cfg(not(unix))]
153+
fn normalize_private_key_permissions(_private_key_path: &std::path::Path) {
154+
// No-op on non-Unix platforms.
155+
}
156+
129157
// =============================================================================
130158
// SSH CONNECTIVITY HELPERS
131159
// =============================================================================
@@ -188,13 +216,15 @@ pub async fn assert_connectivity_succeeds_eventually(client: &SshClient, max_sec
188216
let socket_addr = test_client.ssh_config().socket_addr;
189217
let tcp_probe_result = PortChecker::new().is_port_open(socket_addr);
190218
let one_shot_ssh_result = test_client.test_connectivity();
219+
let one_shot_execute_result = test_client.execute("echo 'SSH connected'");
191220

192221
eprintln!(
193222
"\n=== SSH Connectivity Failure Diagnostics ===\n\
194223
target: {socket_addr}\n\
195224
retry_window_secs: {max_seconds}\n\
196225
raw_tcp_port_open: {tcp_probe_result:?}\n\
197-
one_shot_ssh_connectivity: {one_shot_ssh_result:?}\n"
226+
one_shot_ssh_connectivity: {one_shot_ssh_result:?}\n\
227+
one_shot_ssh_execute: {one_shot_execute_result:?}\n"
198228
);
199229

200230
print_docker_debug_info(socket_addr.port());

0 commit comments

Comments
 (0)