Skip to content

Commit a3a44ad

Browse files
committed
feat!: Edition 2024; ssh2-config 0.4
1 parent 6387e91 commit a3a44ad

14 files changed

+863
-551
lines changed

.github/workflows/linux.yml

+1-2
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ jobs:
1818
- uses: dtolnay/rust-toolchain@stable
1919
with:
2020
toolchain: stable
21-
override: true
2221
components: rustfmt, clippy
2322
- name: Build
2423
run: cargo build --all-features
@@ -29,6 +28,6 @@ jobs:
2928
- name: Clippy
3029
run: cargo clippy --features find -- -Dwarnings
3130
- name: Run tests
32-
run: cargo test --all-features --features find,github-actions,with-containers
31+
run: cargo test --all-features --features find,github-actions
3332
env:
3433
RUST_LOG: trace

CHANGELOG.md

+9-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# Changelog
22

33
- [Changelog](#changelog)
4+
- [0.6.0](#060)
45
- [0.5.0](#050)
56
- [0.4.1](#041)
67
- [0.4.0](#040)
@@ -17,9 +18,16 @@
1718

1819
---
1920

21+
## 0.6.0
22+
23+
Released on 15/03/2025
24+
25+
- bump `ssh2-config` to `0.4.0`
26+
- edition `2024`
27+
2028
## 0.5.0
2129

22-
Released on 26/102/2024
30+
Released on 26/10/2024
2331

2432
- `SshKeyStorage` must be `Sync` and `Send`
2533

Cargo.toml

+6-7
Original file line numberDiff line numberDiff line change
@@ -3,30 +3,30 @@ authors = ["Christian Visintin <[email protected]>"]
33
categories = ["network-programming"]
44
description = "remotefs SSH client library"
55
documentation = "https://docs.rs/remotefs-ssh"
6-
edition = "2021"
6+
edition = "2024"
77
include = ["src/**/*", "LICENSE", "README.md", "CHANGELOG.md"]
88
keywords = ["remotefs", "ssh-client", "scp-client", "sftp-client"]
99
license = "MIT"
1010
name = "remotefs-ssh"
1111
readme = "README.md"
1212
repository = "https://github.com/remotefs-rs/remotefs-rs-ssh"
13-
version = "0.5.0"
14-
rust-version = "1.71.1"
13+
version = "0.6.0"
14+
rust-version = "1.85.0"
1515

1616
[dependencies]
1717
chrono = "^0.4"
1818
lazy-regex = "3"
1919
log = "^0.4"
2020
remotefs = "^0.3"
21-
ssh2-config = "^0.2"
21+
ssh2-config = "^0.4"
2222
ssh2 = "^0.9"
2323

2424
[dev-dependencies]
2525
env_logger = "^0.11"
2626
pretty_assertions = "^1"
27-
rand = "^0.8.4"
28-
serial_test = "^3"
27+
rand = "^0.9"
2928
tempfile = "^3"
29+
testcontainers = { version = "0.23", features = ["blocking"] }
3030

3131
[features]
3232
default = ["find"]
@@ -36,7 +36,6 @@ no-log = ["log/max_level_off"]
3636
ssh2-vendored = ["ssh2/vendored-openssl"]
3737
# tests
3838
github-actions = []
39-
with-containers = []
4039

4140
[target."cfg(target_os = \"windows\")"]
4241
[target."cfg(target_os = \"windows\")".dependencies]

LICENSE

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
MIT License
22

3-
Copyright (c) 2021 Christian Visintin
3+
Copyright (c) 2021-2025 Christian Visintin
44

55
Permission is hereby granted, free of charge, to any person obtaining a copy
66
of this software and associated documentation files (the "Software"), to deal

README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
<p align="center">~ Remotefs SSH client ~</p>
1212

1313
<p align="center">Developed by <a href="https://veeso.github.io/" target="_blank">@veeso</a></p>
14-
<p align="center">Current version: 0.5.0 (26/10/2024)</p>
14+
<p align="center">Current version: 0.6.0 (15/03/2025)</p>
1515

1616
<p align="center">
1717
<a href="https://opensource.org/licenses/MIT"
@@ -82,7 +82,7 @@ First of all, add `remotefs-ssh` to your project dependencies:
8282

8383
```toml
8484
remotefs = "0.3"
85-
remotefs-ssh = "^0.5"
85+
remotefs-ssh = "^0.6"
8686
```
8787

8888
these features are supported:

src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
//!
1212
//! ```toml
1313
//! remotefs = "^0.3"
14-
//! remotefs-ssh = "^0.5"
14+
//! remotefs-ssh = "^0.6"
1515
//! ```
1616
//!
1717
//! these features are supported:

src/mock/mod.rs

+11-1
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,15 @@ pub mod ssh;
66
// -- logger
77

88
pub fn logger() {
9-
let _ = env_logger::builder().is_test(true).try_init();
9+
use std::sync::Once;
10+
11+
static INIT: Once = Once::new();
12+
13+
INIT.call_once(|| {
14+
let _ = env_logger::builder()
15+
.filter_level(log::LevelFilter::Trace)
16+
.is_test(true)
17+
.format_line_number(true)
18+
.try_init();
19+
});
1020
}

src/mock/ssh.rs

+14-10
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,10 @@ pub struct MockSshKeyStorage {
1616
impl Default for MockSshKeyStorage {
1717
fn default() -> Self {
1818
let mut key = NamedTempFile::new().expect("Failed to create tempfile");
19-
assert!(writeln!(
20-
key,
21-
r"-----BEGIN OPENSSH PRIVATE KEY-----
19+
assert!(
20+
writeln!(
21+
key,
22+
r"-----BEGIN OPENSSH PRIVATE KEY-----
2223
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABFwAAAAdzc2gtcn
2324
NhAAAAAwEAAQAAAQEAxKyYUMRCNPlb4ZV1VMofrzApu2l3wgP4Ot9wBvHsw/+RMpcHIbQK
2425
9iQqAVp8Z+M1fJyPXTKjoJtIzuCLF6Sjo0KI7/tFTh+yPnA5QYNLZOIRZb8skumL4gwHww
@@ -45,8 +46,9 @@ ruVXgkd7RJFbsIiD4dDcF4VCjwWHfTK21EOgJUA5pN6TNvAAAAgQDbcJWRx8Uyhkj2+srb
4546
TNKCN34QCWkyuYRHGhcNc0quEDayPw5QWGXlP4BzjfRUcPxY9cCXLe5wDLYsX33HwOAc59
4647
RorU9FCmS/654wAAABFyb290QDhjNTBmZDRjMzQ1YQECAw==
4748
-----END OPENSSH PRIVATE KEY-----"
48-
)
49-
.is_ok());
49+
)
50+
.is_ok()
51+
);
5052
Self { key }
5153
}
5254
}
@@ -64,9 +66,10 @@ impl SshKeyStorage for MockSshKeyStorage {
6466
// -- config file
6567

6668
/// Create ssh config file
67-
pub fn create_ssh_config() -> NamedTempFile {
69+
pub fn create_ssh_config(port: u16) -> NamedTempFile {
6870
let mut temp = NamedTempFile::new().expect("Failed to create tempfile");
69-
let config = r##"
71+
let config = format!(
72+
r##"
7073
# ssh config
7174
Compression yes
7275
ConnectionAttempts 3
@@ -77,13 +80,14 @@ MACs hmac-sha2-512,hmac-sha2-256,hmac-ripemd160
7780
# Hosts
7881
Host sftp
7982
HostName 127.0.0.1
80-
Port 10022
83+
Port {port}
8184
User sftp
8285
Host scp
8386
HostName 127.0.0.1
84-
Port 10222
87+
Port {port}
8588
User sftp
86-
"##;
89+
"##
90+
);
8791
temp.write_all(config.as_bytes()).unwrap();
8892
temp
8993
}

src/ssh/commons.rs

+35-16
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ use std::time::Duration;
1111
use remotefs::{RemoteError, RemoteErrorType, RemoteResult};
1212
use ssh2::{MethodType as SshMethodType, Session};
1313

14-
use super::config::Config;
1514
use super::SshOpts;
15+
use super::config::Config;
1616
use crate::SshAgentIdentity;
1717

1818
// -- connect
@@ -30,7 +30,7 @@ pub fn connect(opts: &SshOpts) -> RemoteResult<Session> {
3030
return Err(RemoteError::new_ex(
3131
RemoteErrorType::BadAddress,
3232
err.to_string(),
33-
))
33+
));
3434
}
3535
};
3636
let mut stream = None;
@@ -312,7 +312,7 @@ pub fn perform_shell_cmd<S: AsRef<str>>(session: &mut Session, cmd: S) -> Remote
312312
return Err(RemoteError::new_ex(
313313
RemoteErrorType::ProtocolError,
314314
format!("Could not open channel: {err}"),
315-
))
315+
));
316316
}
317317
};
318318
// Execute command
@@ -364,7 +364,7 @@ pub fn perform_shell_cmd_with_rc<S: AsRef<str>>(
364364
return Err(RemoteError::new_ex(
365365
RemoteErrorType::ProtocolError,
366366
"Failed to get command exit code",
367-
))
367+
));
368368
}
369369
};
370370
debug!(r#"Command output: "{}"; exit code: {}"#, actual_output, rc);
@@ -383,18 +383,21 @@ pub fn perform_shell_cmd_with_rc<S: AsRef<str>>(
383383
#[cfg(test)]
384384
mod test {
385385

386-
#[cfg(feature = "with-containers")]
387386
use ssh2_config::ParseRule;
388387

389388
use super::*;
390-
#[cfg(feature = "with-containers")]
391389
use crate::mock::ssh as ssh_mock;
392390

393391
#[test]
394-
#[cfg(feature = "with-containers")]
392+
395393
fn should_connect_to_ssh_server_auth_user_password() {
394+
use crate::ssh::container::OpensshServer;
395+
396+
let container = OpensshServer::start();
397+
let port = container.port();
398+
396399
crate::mock::logger();
397-
let config_file = ssh_mock::create_ssh_config();
400+
let config_file = ssh_mock::create_ssh_config(port);
398401
let opts = SshOpts::new("sftp")
399402
.config_file(config_file.path(), ParseRule::ALLOW_UNKNOWN_FIELDS)
400403
.password("password");
@@ -404,13 +407,20 @@ mod test {
404407
}
405408
let session = connect(&opts).unwrap();
406409
assert!(session.authenticated());
410+
411+
drop(container);
407412
}
408413

409414
#[test]
410-
#[cfg(feature = "with-containers")]
415+
411416
fn should_connect_to_ssh_server_auth_key() {
417+
use crate::ssh::container::OpensshServer;
418+
419+
let container = OpensshServer::start();
420+
let port = container.port();
421+
412422
crate::mock::logger();
413-
let config_file = ssh_mock::create_ssh_config();
423+
let config_file = ssh_mock::create_ssh_config(port);
414424
let opts = SshOpts::new("sftp")
415425
.config_file(config_file.path(), ParseRule::ALLOW_UNKNOWN_FIELDS)
416426
.key_storage(Box::new(ssh_mock::MockSshKeyStorage::default()));
@@ -419,11 +429,14 @@ mod test {
419429
}
420430

421431
#[test]
422-
#[cfg(feature = "with-containers")]
432+
423433
fn should_perform_shell_command_on_server() {
424434
crate::mock::logger();
435+
let container = crate::ssh::container::OpensshServer::start();
436+
let port = container.port();
437+
425438
let opts = SshOpts::new("127.0.0.1")
426-
.port(10022)
439+
.port(port)
427440
.username("sftp")
428441
.password("password");
429442
let mut session = connect(&opts).unwrap();
@@ -433,11 +446,14 @@ mod test {
433446
}
434447

435448
#[test]
436-
#[cfg(feature = "with-containers")]
449+
437450
fn should_perform_shell_command_on_server_and_return_exit_code() {
438451
crate::mock::logger();
452+
let container = crate::ssh::container::OpensshServer::start();
453+
let port = container.port();
454+
439455
let opts = SshOpts::new("127.0.0.1")
440-
.port(10022)
456+
.port(port)
441457
.username("sftp")
442458
.password("password");
443459
let mut session = connect(&opts).unwrap();
@@ -459,11 +475,14 @@ mod test {
459475
}
460476

461477
#[test]
462-
#[cfg(feature = "with-containers")]
478+
463479
fn should_fail_authentication() {
464480
crate::mock::logger();
481+
let container = crate::ssh::container::OpensshServer::start();
482+
let port = container.port();
483+
465484
let opts = SshOpts::new("127.0.0.1")
466-
.port(10022)
485+
.port(port)
467486
.username("sftp")
468487
.password("ippopotamo");
469488
assert!(connect(&opts).is_err());

src/ssh/config.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -160,21 +160,21 @@ mod test {
160160

161161
#[test]
162162
fn should_init_config_from_file() {
163-
let config_file = ssh_mock::create_ssh_config();
163+
let config_file = ssh_mock::create_ssh_config(22);
164164
let opts = SshOpts::new("sftp").config_file(config_file.path(), ParseRule::STRICT);
165165
let config = Config::try_from(&opts).ok().unwrap();
166166
assert_eq!(config.connection_attempts, 3);
167167
assert_eq!(config.connection_timeout, Duration::from_secs(60));
168168
assert_eq!(config.host.as_str(), "sftp");
169169
assert_eq!(config.resolved_host.as_str(), "127.0.0.1");
170-
assert_eq!(config.address.as_str(), "127.0.0.1:10022");
170+
assert_eq!(config.address.as_str(), "127.0.0.1:22");
171171
assert_eq!(config.username.as_str(), "sftp");
172172
assert_ne!(config.params, HostParams::default());
173173
}
174174

175175
#[test]
176176
fn should_init_config_from_file_with_override() {
177-
let config_file = ssh_mock::create_ssh_config();
177+
let config_file = ssh_mock::create_ssh_config(22);
178178
let opts = SshOpts::new("sftp")
179179
.config_file(config_file.path(), ParseRule::STRICT)
180180
.connection_timeout(Duration::from_secs(10))

0 commit comments

Comments
 (0)