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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,4 @@ Thumbs.db
.claude/
.gemini/
references/
vendor/
103 changes: 39 additions & 64 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

19 changes: 19 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ A high-performance SSH client with **SSH-compatible syntax** for both single-hos
## Features

- **SSH Compatibility**: Drop-in replacement for SSH with compatible command-line syntax
- **Jump Host Support**: Connect through bastion hosts using OpenSSH ProxyJump syntax (`-J`)
- **Parallel Execution**: Execute commands across multiple nodes simultaneously
- **Cluster Management**: Define and manage node clusters via configuration files
- **Progress Tracking**: Real-time progress indicators for each node
Expand Down Expand Up @@ -98,6 +99,24 @@ bssh -o StrictHostKeyChecking=no user@host
bssh -Q cipher
```

### Jump Host Support (ProxyJump)
```bash
# Connect through a single jump host (bastion)
bssh -J jump@bastion.example.com user@internal-server

# Multiple jump hosts (connection chain)
bssh -J "jump1@proxy1,jump2@proxy2" user@final-destination

# Jump host with custom port
bssh -J admin@bastion:2222 user@internal-host

# IPv6 jump host
bssh -J "[2001:db8::1]:22" user@destination

# Combine with cluster operations
bssh -J bastion.example.com -C production "uptime"
```

### Multi-Server Mode (Cluster Operations)
```bash
# Using direct host specification
Expand Down
15 changes: 7 additions & 8 deletions src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,13 @@ pub struct Cli {
)]
pub password: bool,

#[arg(
short = 'J',
long = "jump-host",
help = "Comma-separated list of jump hosts (ProxyJump)\nSpecify in [user@]hostname[:port] format, e.g.: 'jump1.example.com' or 'user@jump1:2222,jump2'\nSupports multiple hops for complex network topologies"
)]
pub jump_hosts: Option<String>,

#[arg(
long = "parallel",
default_value = "10",
Expand Down Expand Up @@ -160,14 +167,6 @@ pub struct Cli {
)]
pub no_tty: bool,

#[arg(
short = 'J',
long = "jump",
value_name = "destination",
help = "Connect via jump host(s) (ProxyJump)"
)]
pub jump_hosts: Option<String>,

#[arg(short = 'x', long = "no-x11", help = "Disable X11 forwarding")]
pub no_x11: bool,

Expand Down
4 changes: 3 additions & 1 deletion src/commands/exec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ pub struct ExecuteCommandParams<'a> {
pub use_password: bool,
pub output_dir: Option<&'a Path>,
pub timeout: Option<u64>,
pub jump_hosts: Option<&'a str>,
}

pub async fn execute_command(params: ExecuteCommandParams<'_>) -> Result<()> {
Expand All @@ -49,7 +50,8 @@ pub async fn execute_command(params: ExecuteCommandParams<'_>) -> Result<()> {
params.use_agent,
params.use_password,
)
.with_timeout(params.timeout);
.with_timeout(params.timeout)
.with_jump_hosts(params.jump_hosts.map(|s| s.to_string()));

let results = executor.execute(params.command).await?;

Expand Down
17 changes: 14 additions & 3 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -720,11 +720,22 @@ mod tests {

#[test]
fn test_expand_tilde() {
unsafe {
std::env::set_var("HOME", "/home/user");
}
// Save original HOME value
let original_home = std::env::var("HOME").ok();

// Set test HOME value
std::env::set_var("HOME", "/home/user");

let path = Path::new("~/.ssh/config");
let expanded = expand_tilde(path);

// Restore original HOME value
if let Some(home) = original_home {
std::env::set_var("HOME", home);
} else {
std::env::remove_var("HOME");
}

assert_eq!(expanded, PathBuf::from("/home/user/.ssh/config"));
}

Expand Down
Loading