From 25cf1644618aa7898f3881798ca4bf10a511a582 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=89=E6=AD=A3=E8=B6=85?= Date: Tue, 12 May 2026 18:40:23 +0800 Subject: [PATCH] test(protocols): cover SFTP host key reload failure (#2928) Co-authored-by: houseme --- crates/protocols/src/sftp/server.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/crates/protocols/src/sftp/server.rs b/crates/protocols/src/sftp/server.rs index 92beb2f1d..7d7878ae9 100644 --- a/crates/protocols/src/sftp/server.rs +++ b/crates/protocols/src/sftp/server.rs @@ -599,6 +599,26 @@ mod hot_reload_tests { assert_eq!(reloaded, None); } + #[tokio::test] + async fn ssh_config_holder_reload_failure_keeps_current_host_keys() { + let dir = TempDir::new().expect("tempdir"); + write_file_with_mode(&dir.path().join("ssh_host_ed25519_key"), &test_ed25519_pem(), 0o600); + + let config = test_config(dir.path()); + let initial_keys = SftpConfig::load_host_keys(dir.path()).await.expect("initial key load"); + let holder = SshConfigHolder::new(build_ssh_config(initial_keys, config.idle_timeout_secs, &config.banner)); + assert!(matches!(holder.get().keys[0].algorithm(), russh::keys::Algorithm::Ed25519)); + + std::fs::remove_file(dir.path().join("ssh_host_ed25519_key")).expect("remove old key"); + + let err = holder + .reload_from_config(&config) + .await + .expect_err("empty host key directory must fail reload"); + assert!(matches!(err, SftpInitError::NoHostKeysFound { .. })); + assert!(matches!(holder.get().keys[0].algorithm(), russh::keys::Algorithm::Ed25519)); + } + #[tokio::test] async fn fingerprint_host_keys_is_order_independent() { let dir = TempDir::new().expect("tempdir");