bssh 2.1.2

Parallel SSH command execution tool for cluster management
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
# Changelog

All notable changes to bssh will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

## [2.1.2] - 2026-04-27

### Fixed
- **PTY session mouse tracking leak**: after a PTY session disconnects (normal exit, Ctrl+C, network drop, or panic), the local terminal no longer prints raw SGR mouse escape sequences when the mouse is moved. All cleanup paths (`TerminalStateGuard::Drop`, `force_terminal_cleanup`, and the panic hook via `TerminalGuard`) now emit the full set of mouse-tracking-off sequences (modes 1000, 1002, 1003, 1006, 1015) plus cursor-show and alternate-screen-exit on teardown. (#189, #190)
- **Panic-hook safety in terminal cleanup**: `force_terminal_cleanup()` now uses `try_lock()` instead of `lock()` so the panic hook path (`TerminalGuard::restore_terminal``force_terminal_cleanup`) cannot deadlock if the panicking thread already holds `TERMINAL_MUTEX`, and a previously poisoned mutex no longer triggers a secondary panic. The lock only serializes concurrent teardown; the underlying stdout writes and `disable_raw_mode` are individually safe. (#190)

### Changed
- Centralized terminal teardown logic: `TerminalGuard::restore_terminal()` in `interactive_signal.rs` now delegates to `force_terminal_cleanup()` instead of carrying its own incomplete cleanup, closing the gap on the panic-hook path.

### Tests
- Added unit tests for `force_terminal_cleanup()` covering idempotency, poisoned-mutex resilience, and held-mutex resilience (using local `Mutex` instances rather than the global `TERMINAL_MUTEX` to keep the global state undisturbed).

### CI/CD
- Trigger the Homebrew formula update workflow only after the official release: `release.yml` now calls `update_homebrew_formula.yml` via `workflow_call` from the `publish-release` job (which converts pre-release to official), instead of `workflow_run` firing on every Release workflow completion (including pre-release builds).
- Prevent the release workflow from being triggered twice: removed the `published` event type from the trigger list since `publish-release` already handles the pre-release → official conversion. `workflow_dispatch` continues to cover manual runs.

## [2.1.1] - 2026-04-17

### Fixed
- **bssh-server panic on client connection**: `new_client_with_addr` called `block_on()` inside the tokio async runtime to check the auth rate limiter ban list, causing an immediate "Cannot start a runtime from within a runtime" panic on every incoming connection. Added non-blocking `AuthRateLimiter::try_is_banned()` using `RwLock::try_read()`. (#185)
- **bssh-server auth rejection after successful verification**: All `SshHandler` constructors created a local `SessionInfo` that was never registered with `SessionManager`. After public key or password verification succeeded, `authenticate_session()` returned `SessionNotFound`, rejecting the client. Fixed by deferring session creation to the authentication flow via `SessionManager::create_session()`. (#185)

### Changed
- Improved Launchpad PPA packaging for Rust 2024 edition: updated `debian/rules` variants, added `debian/sanitize-vendor.py` for vendored crate checksum sanitization, fixed hidden path handling
- Added `.pyc` files to `.gitignore`

## [2.1.0] - 2026-04-14

### Added
- `EnvGuard` RAII wrapper (`src/test_helpers/env_guard.rs`) for safe environment variable handling in tests, with Drop-based restore semantics and soundness contract documentation (#179, #181)
- Test Environment-Variable Mutation Pattern section in ARCHITECTURE.md documenting the `EnvGuard` soundness contract and `#[serial]` usage

### Changed
- Migrated bssh and the bundled `bssh-russh` crate to the Rust 2024 edition
- Applied 2024 edition clippy improvements: collapsed 38 nested `if let` statements into guard-clause form (`if let Some(x) = y && condition`) across `bssh-russh` client/server/keys/kex modules
- Replaced 177 ad-hoc `unsafe { env::set_var/remove_var }` call sites across 17 test-bearing files with `EnvGuard::set` / `EnvGuard::remove` plus `#[serial]` from the `serial_test` crate
- Removed hand-rolled `ENV_MUTEX` / `once_cell::sync::Lazy<Mutex<()>>` pattern in integration tests in favor of `#[serial]`
- Pinned `bytes` dependency to v1.11.1

### Fixed
- Fixed pattern matching for Rust 2024 edition: removed explicit `ref` / `ref mut` bindings in `if let` patterns in `src/server/handler.rs` and `src/server/shell.rs`

## [2.0.1] - 2026-04-13

### Added
- bssh-keygen now included in Debian package build pipeline for all architectures

### Changed
- Bumped bssh-russh from 0.60.0 to 0.60.1 with security updates

### Fixed
- Fixed GitHub Actions debian_build.yml distro configuration (questing -> resolute)
- Fixed debian_build.yml matrix validation issue causing workflow failures

### Security
- Updated rsa to 0.10.0-rc.17 (fixes RUSTSEC-2023-0071 RSA Marvin Attack)
- Updated RC dependencies to latest versions: elliptic-curve 0.14.0-rc.30, p256/p384/p521 0.14.0-rc.8, ml-kem 0.3.0-rc.2, spki 0.8.0 (stable)

## [2.0.0] - 2026-04-13

### Added
- **bssh-server SSH Server** - A lightweight SSH server designed for container environments
  - Full SSH, SFTP, and SCP protocol support
  - PTY/shell session support with terminal handling
  - Password and public key authentication
  - YAML-based comprehensive configuration system
  - Command execution handler with security controls

- **Audit Logging Infrastructure**
  - File-based audit exporter (JSON Lines format)
  - OpenTelemetry audit exporter for observability platforms
  - Logstash audit exporter for ELK stack integration
  - Configurable audit event types and logging levels

- **Security Features**
  - IP-based access control (allow/deny lists)
  - Authentication rate limiting (fail2ban-like protection)
  - Session management and connection limits
  - Path traversal prevention in SFTP handler

- **File Transfer Filtering**
  - Path-based filter rules for upload/download control
  - Pattern-based filtering with glob support
  - Configurable filter actions (allow/deny)

- **bssh-keygen Tool**
  - SSH key pair generation utility
  - Support for RSA, Ed25519, and ECDSA key types
  - Configurable key sizes and comments

- **Server Configuration**
  - Per-jump-host SSH private key configuration
  - SSH config Host alias reference in jump_host configuration
  - SSH keepalive settings in interactive mode

- **Separate Packaging**
  - bssh and bssh-server now distributed as separate packages
  - Independent Debian packages for client and server
  - Separate Homebrew formulas for each component

### Changed
- **Documentation**: Added comprehensive server configuration manual and manpages
- **CI/CD**: Updated release workflow for dual-package distribution; Teams release notification added
- **Dependencies**: Synced bssh-russh fork with upstream `warp-tech/russh` v0.60.0, which brings the RustCrypto chain migration — rand 0.9 → **0.10 stable**, signature 3.0.0-rc.10, ed25519-dalek 3.0.0-pre.6, elliptic-curve 0.14.0-rc.28, p256/p384/p521 0.14.0-rc.7, ecdsa 0.17.0-rc.16, curve25519-dalek 5.0.0-pre.6, der 0.8, sec1 0.8, pkcs8 0.11.0-rc.11, pkcs5 0.8.0-rc.13, spki 0.8.0-rc.4, ml-kem 0.3.0-rc.1, ssh-key 0.6.18, tokio 1.51.1, socket2 0.6.3, signal-hook 0.4.4, fastrand 2.4.1
- **Cluster flag help**: Help examples and man pages now correctly show `-C` (uppercase) for the cluster flag; running the previous `-c` examples failed with clap's "unexpected argument" error

### Fixed
- **SSH idle disconnects**: Interactive sessions could disconnect inconsistently after idle time — sometimes within minutes, sometimes ~10 minutes
  - `russh::Config::inactivity_timeout` (10-minute client-side ceiling) is now explicitly set to `None` when keepalive is enabled so the keepalive mechanism alone decides peer liveness
  - TCP-level `SO_KEEPALIVE` (via `socket2::TcpKeepalive`) is now applied to every SSH socket so the kernel can detect broken paths even when SSH keepalive replies are dropped by middleboxes
  - The exec-mode code path previously dropped the user-configured `SshConnectionConfig` at the `ConnectionConfig` boundary; it now flows through `connect_direct` / `connect_via_jump_hosts` / the jump chain, so `server_alive_interval` actually takes effect in non-interactive runs
- **bssh-server**: Use consistent source package name in Debian `control` file so dual-package builds resolve correctly
- **bssh-server**: Use type inference for `ioctl` to support both glibc and musl builds

### Technical Details
- Shared module structure for client/server code reuse
- russh-based SSH server handler implementation
- Modular audit exporter architecture with trait-based design
- `SshConnectionConfig::to_russh_config()` now overrides `inactivity_timeout` based on keepalive state; `to_tcp_keepalive()` derives a kernel TCP keepalive config from the same settings
- `Client::connect_with_config` rewritten around `russh::client::connect_stream`, building the `TcpStream` manually so SO_KEEPALIVE can be applied before the SSH handshake
- Dropped the `ssh_key::rand_core::OsRng` workaround in key-generation sites; now pass `&mut rand::rng()` (rand 0.10's thread RNG implements the new `rand_core 0.10` `CryptoRng` trait directly)

## [1.7.0] - 2026-01-09

### Added
- **SSH Keepalive Support** (Issue #122)
  - `--server-alive-interval` option: Configure keepalive interval in seconds (default: 60, 0 to disable)
  - `--server-alive-count-max` option: Maximum keepalive messages without response before disconnect (default: 3)
  - Configuration support in config.yaml via `server_alive_interval` and `server_alive_count_max` fields
  - Helps maintain long-running sessions through firewalls and NATs that drop idle connections
  - Full integration with exec, interactive, and file transfer modes

### Changed
- **Documentation**: Added GitHub downloads badge to README

### Dependencies
- Updated russh from 0.55.0 to 0.56.0
- Updated ratatui from 0.29.0 to 0.30.0
- Updated signal-hook from 0.3.18 to 0.4.1
- Updated whoami from 1.6.1 to 2.0.1
- Updated unicode-width from 0.2.0 to 0.2.2

### Technical Details
- Implemented SSH keepalive packet sending at configurable intervals
- Automatic connection termination after max retries without response
- Keepalive settings work with jump host connections
- Adapted to whoami 2.0 API changes (username() now returns Result)

## [1.6.0] - 2025-12-19

### Added
- **Jump Host Configuration Support in YAML** (Issue #115, PR #120)
  - Global defaults level: `defaults.jump_host` for all clusters
  - Cluster level: `clusters.<name>.jump_host` for cluster-specific settings
  - Node level: Per-node `jump_host` in detailed node configuration
  - Environment variable expansion supported (`${VAR}` or `$VAR` syntax)
  - Empty string (`""`) explicitly disables jump host inheritance
  - CLI `-J` option always takes precedence over configuration

### Changed
- **SSH Config ProxyJump Directive** (Issue #117, PR #119)
  - ProxyJump directive from SSH config now properly applied when `-J` option not specified
  - Priority order: CLI `-J` > config.yaml jump_host > SSH config ProxyJump
- **Documentation Improvements**
  - Added comprehensive jump_host configuration documentation to README.md
  - Updated docs/architecture/ssh-jump-hosts.md with detailed architecture
  - Updated example-config.yaml with all jump_host configuration patterns
- **CI/CD**
  - Updated GitHub workflows

### Fixed
- **Jump Host Authentication** (Issue #116, PR #118)
  - Properly handle empty SSH agent when authenticating through jump hosts
  - Fall back to key-based authentication when agent has no identities
- **Config Fallback** (PR #120)
  - Environment variables now properly expanded in jump_host values via expand_env_vars
  - Configuration jump_host properly used in exec and interactive modes

### Technical Details
- Added `ConfigResolver::resolve_jump_host()` method for centralized jump host resolution
- Jump host priority: CLI > Node > Cluster > Global defaults
- Comprehensive test coverage: 424 lines of tests for jump_host configuration
- Integration tests for all priority levels and edge cases

## [1.5.1] - 2025-12-18

### Fixed
- **SSH Disconnect Error Handling** (Issue #113, PR #114)
  - Handle SshError(Disconnect) during authentication for password fallback
  - Fixed handling of SSH disconnect errors during authentication phase
  - Enables proper password fallback when SSH connection is disconnected during auth

## [1.5.0] - 2025-12-18

### Added
- **pdsh Compatibility Mode** (Issues #100-103, #105, #107, #110)
  - Full pdsh-style command line compatibility when invoked as `pdsh` or with `--pdsh-compat`
  - `-w hosts` option mapped to `-H hosts` for target host specification
  - `-x hosts` option mapped to `--exclude hosts` for host exclusion
  - `-f N` option mapped to `--parallel N` for fanout control
  - `-l user` option for remote username
  - `-t N` option mapped to `--connect-timeout N` for connection timeout
  - `-u N` option mapped to `--timeout N` for command timeout
  - `-N` option mapped to `--no-prefix` for disabling hostname prefix in output
  - `-b` option mapped to `--batch` for single Ctrl+C termination
  - `-k` option mapped to `--fail-fast` for stop on first failure
  - `-q` query mode to show target hosts and exit
  - `-S` option mapped to `--any-failure` for returning largest exit code

- **Hostlist Expressions** (Issue #107)
  - pdsh-style range expansion: `node[1-5]` → node1, node2, node3, node4, node5
  - Zero-padded ranges: `node[01-05]` → node01, node02, node03, node04, node05
  - Comma-separated values: `node[1,3,5]` → node1, node3, node5
  - Cartesian product: `rack[1-2]-node[1-3]` → 6 hosts
  - Domain suffix support: `web[1-3].example.com`
  - User and port preservation: `admin@db[01-03]:5432`
  - File input with `^/path/to/hostfile`

- **In-TUI Log Panel** (Issue #106)
  - Toggle visibility with `l` key
  - Color-coded by level: ERROR (red), WARN (yellow), INFO (white), DEBUG (gray)
  - Configurable buffer size via `BSSH_TUI_LOG_MAX_ENTRIES` (default: 1000, max: 10000)
  - Panel height adjustable from 3-10 lines with `+`/`-` keys
  - Scroll with `j`/`k` keys, toggle timestamps with `t`

- **--fail-fast Option** (Issue #103)
  - `-k` / `--fail-fast` flag to stop immediately on first failure
  - Compatible with pdsh `-k` option
  - Cancels pending commands when any node fails
  - Can be combined with `--require-all-success` for strict error handling

- **--batch Option** (Issue #102)
  - `-b` / `--batch` flag for single Ctrl+C termination
  - Compatible with pdsh `-b` option
  - Useful for non-interactive scripts and CI/CD pipelines

- **--exclude Option** (Issue #100)
  - `--exclude` / `-x` for host exclusion
  - Supports wildcards, glob patterns, and hostlist expressions
  - Applied after `--filter` option

- **--no-prefix Option** (Issue #101)
  - `-N` / `--no-prefix` for disabling hostname prefix in output
  - Compatible with pdsh `-N` option
  - Works with both stream mode and file mode

- **--connect-timeout Option** (PR #103)
  - Separate connection timeout from command execution timeout
  - Default: 30 seconds, minimum: 1 second
  - Useful for fast failure detection on unreachable hosts

### Changed
- **CI Workflow Simplification**
  - Merged multiple jobs into single pipeline for efficiency

### Fixed
- **--timeout 0 Handling** (Issue #112)
  - Fixed --timeout 0 to correctly treat as unlimited execution time
  - Previously the 0 value was being ignored, causing unexpected timeout behavior
  - Added explicit CLI test to prevent regression

- **Environment Variable Test Race Conditions**
  - Added `#[serial]` attribute to env var tests to prevent race conditions
  - Tests now run sequentially when accessing shared environment state

- **Connect Timeout Propagation**
  - Fixed connect_timeout not being propagated through all SSH connection paths

### Documentation
- **Architecture Restructure** (Issue #109)
  - Restructured ARCHITECTURE.md into modular documentation
  - Removed residual dates and fixed incomplete sentences

- **pdsh Compatibility Documentation** (Issue #110)
  - Added comprehensive pdsh migration guide (docs/pdsh-migration.md)
  - Added pdsh options reference (docs/pdsh-options.md)
  - Added pdsh usage examples (docs/pdsh-examples.md)
  - Added installation scripts for pdsh symlink setup

## [1.4.2] - 2025-12-16

### Fixed
- **PTY Session Terminal Handling** (PR #90)
  - Fixed terminal escape sequence responses displayed on first prompt when starting tmux
  - Improved terminal compatibility with multiplexers
- **PTY Session Paste** (PR #89)
  - Fixed paste not working in PTY sessions
  - Improved clipboard/paste functionality in interactive terminal sessions

### Changed
- **Dependencies**
  - Bumped dependencies to latest versions for security and compatibility

## [1.4.1] - 2025-12-16

### Added
- **Comprehensive Test Suite** (Issue #82, PR #86)
  - tests/tui_snapshot_tests.rs: 20 tests for TUI rendering using ratatui's TestBackend
  - tests/tui_event_tests.rs: 36 tests for keyboard navigation, scroll behavior, and view transitions
  - tests/streaming_integration_tests.rs: 28 tests for NodeStream, MultiNodeStreamManager, and streaming execution
  - benches/large_output_benchmark.rs: Performance benchmarks for large output handling
  - Total: 84 new tests added

### Fixed
- **SSH Agent Password Fallback** (Issue #84, PR #85)
  - Extended password fallback to handle all SSH agent authentication failures
  - Now correctly triggers for: AgentAuthenticationFailed, AgentNoIdentities, AgentConnectionFailed, AgentRequestIdentitiesFailed
  - Added `is_auth_error_for_password_fallback()` helper function for testability
  - Added unit tests and integration tests for all error types

### Documentation
- **TUI Module Documentation** (Issue #81, PR #83)
  - Added comprehensive TUI architecture section to ARCHITECTURE.md
  - Enhanced README.md with keyboard shortcuts reference table
  - Added view modes description table
  - Added TUI activation conditions and requirements
  - Added missing "1-9: Jump to node N" shortcut in detail view help text

### Dependencies
- Added insta 1.34 (snapshot testing)
- Added criterion 0.5 (benchmarking)
- Added mockall 0.12 (mocking for integration tests)

### Technical Details
- Refactored test code quality: removed unused functions, replaced panic! with matches! macro
- Added Unicode test cases (Korean, Chinese, Emoji)
- Improved assertion messages for better debugging

## [1.4.0] - 2025-12-15

### Added
- **Sudo Password Support** (Issue #74, PR #78)
  - `-S/--sudo-password` flag for automated sudo authentication
  - Securely prompts for sudo password before command execution
  - Automatically detects and responds to sudo password prompts
  - Works with both streaming and non-streaming execution modes
  - `BSSH_SUDO_PASSWORD` environment variable support (with security warnings)
  - Uses `secrecy` crate for secure memory handling
  - Password cleared from memory immediately after use
- **Developer Tooling**
  - Added githooks for development workflow
  - Setup script for githooks configuration

### Fixed
- **Password Fallback** (PR #80)
  - Improved SSH debugging for better compatibility
  - Enhanced password authentication fallback logic
- Fixed clippy warnings for useless_vec and same_item_push

## [1.3.0] - 2025-12-10

### Added
- **Interactive TUI (Terminal User Interface)** (Phase 3 of #68)
  - Summary view: All nodes at a glance with progress bars
  - Detail view (1-9): Full output from specific node with scrolling
  - Split view (s): Monitor 2-4 nodes simultaneously
  - Diff view (d): Compare output from two nodes side-by-side
  - Auto-scroll (f): Toggle automatic scrolling
  - Navigation: Arrow keys, PgUp/PgDn, Home/End
  - Help (?): Show keyboard shortcuts
  - Press `q` to quit
- **Multi-node Stream Management** (Phase 2 of #68)
  - Real-time output modes for multi-node operations
  - Stream mode with [node] prefixes for real-time monitoring
  - Enhanced streaming infrastructure for real-time updates

### Fixed
- **PTY Escape Sequence Filtering** (PR #77)
  - Filter terminal escape sequence responses in PTY sessions
  - Fixed issue with terminal response codes appearing in output

### Technical Details
- Implemented ratatui-based TUI rendering
- Added multi-node output aggregation and display
- Performance optimizations for real-time output streaming

## [1.2.2] - 2025-10-29

### Fixed
- **Backend.AI Auto-detection** (PR #66)
  - Improved host heuristics for Backend.AI environments
  - Added localhost and localhost.localdomain detection
  - Added IPv4 address validation (127.0.0.1, 192.168.x.x, etc.)
  - Enhanced detection for user@host, host:port, FQDN, IPv6 patterns
  - Users can now use `bssh localhost "command"` naturally in Backend.AI

### Technical Details
- Extracted testable `looks_like_host_specification()` function
- Added `is_ipv4_address()` helper with strict validation
- Performance optimized with early returns
- 16 comprehensive tests added for host detection logic

## [1.2.1] - 2025-10-28

### Fixed
- **Password Authentication Fallback in Interactive Mode** (PR #65)
  - Re-implemented password authentication fallback logic for interactive mode
  - Fixed issue where password prompt was not appearing after key-based authentication failed
  - Ensured proper authentication flow in interactive sessions
- **Test Race Condition** (commit d2e8ce9)
  - Added `#[serial]` attribute to tests calling `RankDetector` to prevent environment variable race conditions
  - Tests now run sequentially when accessing shared environment state
  - Prevents intermittent test failures due to concurrent environment variable access

## [1.2.0] - 2025-10-27

### BREAKING CHANGES
- **Exit code behavior changed** (Issue #62)
  - **Old behavior (v1.0-v1.1)**: Returns 0 only if all nodes succeeded, 1 if any failed
  - **New behavior (v1.2.0+)**: Returns main rank's actual exit code (matches MPI standard: mpirun, srun, mpiexec)
  - **Impact**: Users relying on "all nodes must succeed" semantics must add `--require-all-success` flag
  - **Benefit**: Preserves actual exit codes (139=SIGSEGV, 137=OOM, 124=timeout) for better diagnostics
  - **MPI users**: No changes needed - behavior improved and matches standard tools
  - **Health checks**: Add `--require-all-success` flag to preserve old behavior

### Added
- **Exit Code Strategy** (Issue #62)
  - Main rank exit code returned by default (matches MPI standard: mpirun, srun, mpiexec)
  - Preserves actual exit codes: 139 (SIGSEGV), 137 (OOM), 124 (timeout), etc.
  - `--require-all-success` flag for v1.0-v1.1 behavior (returns 0 only if all nodes succeed)
  - `--check-all-nodes` flag for hybrid mode (main rank code + all-node check)
  - Automatic main rank detection via `BACKENDAI_CLUSTER_ROLE` environment variable
  - Example scripts: `examples/mpi_exit_code.sh`, `examples/health_check.sh`

### Changed
- Exit code behavior now aligns with HPC and distributed computing best practices
- Enables sophisticated error handling in shell scripts and CI/CD pipelines

## [1.1.0] - 2025-10-24

### Added
- **macOS Keychain Integration** (Issue #59, PR #61)
  - Automatic passphrase storage in macOS Keychain after successful SSH key authentication
  - Automatic passphrase retrieval before prompting user
  - Secure memory handling with `Zeroizing` for all sensitive data
  - Integration with SSH config `UseKeychain` option per host
  - New module `src/ssh/keychain_macos.rs` with complete Keychain API wrapper
- **ProxyUseFdpass SSH Option** (Issue #58, PR #60)
  - Added `ProxyUseFdpass` SSH configuration option support
  - Optimizes ProxyCommand usage by passing connected file descriptors back to ssh
  - Reduces overhead from lingering processes and extra read/write operations
- **Password Authentication Fallback**
  - Automatic password retry when publickey authentication fails
  - Matches OpenSSH standard behavior for seamless user experience
  - Interactive terminal detection with TTY checks
  - Works for both exec and interactive modes

### Security
- **SSH Key File Ownership Validation** (PR #61)
  - Prevents storing passphrases for SSH keys owned by other users
  - Added macOS user ID checks using libc
  - World-readable SSH key permission warnings
- **User Consent for Password Fallback** (PR #61)
  - Explicit user consent prompt before attempting password authentication
  - 30-second timeout for consent prompt
  - Prevents unexpected password prompts that could lead to credential exposure
- **Rate Limiting** (PR #61)
  - 100ms delay before initial connection attempts
  - 1 second delay before password fallback
  - Prevents brute-force attacks and fail2ban triggers

### Improved
- **Code Quality** (PR #61)
  - Eliminated 251 lines of code duplication in connection logic
  - Created `establish_connection()` helper function
  - Centralized authentication logic in auth module
  - 60% reduction in connection.rs complexity
- **Cross-Platform Support**
  - All macOS-specific code properly isolated with `#[cfg(target_os = "macos")]`
  - Conditional imports to prevent unused code warnings on non-macOS platforms
  - Stub functions for API consistency across platforms

### Fixed
- Fixed clippy warnings on non-macOS platforms (unused_mut, unused_imports, dead_code)
  - Variable shadowing for macOS-specific code paths
  - Conditional imports for platform-specific functions
- Fixed interactive mode missing `use_keychain` field causing authentication failures
- Fixed password prompt not appearing when connecting to new servers in interactive mode

### Dependencies
- Added `security-framework = "2.12.1"` for macOS Keychain API integration
- Added `libc` for macOS user ID checks (conditional on macOS)

## [1.0.0] - 2025-10-24

### Added
- **SSH Configuration: Certificate Authentication Options**
  - `CertificateFile` - Specify SSH certificate files for PKI authentication (maximum 100 certificates)
  - `CASignatureAlgorithms` - Define CA signature algorithms for certificate validation (maximum 50 algorithms)
  - `HostbasedAuthentication` - Enable/disable host-based authentication
  - `HostbasedAcceptedAlgorithms` - Specify accepted algorithms for host-based authentication (maximum 50 algorithms)

- **SSH Configuration: Advanced Port Forwarding Control**
  - `GatewayPorts` - Control remote port forwarding access (yes/no/clientspecified)
  - `ExitOnForwardFailure` - Terminate connection when port forwarding fails
  - `PermitRemoteOpen` - Specify allowed destinations for remote TCP port forwarding (maximum 1000 entries)

- **SSH Configuration: Command Execution and Automation Options**
  - `PermitLocalCommand` - Allow execution of local commands after successful SSH connection (yes/no, default: no)
  - `LocalCommand` - Execute local command after connection with token substitution support (%h, %H, %n, %p, %r, %u, %%)
  - `RemoteCommand` - Execute command on remote host instead of starting interactive shell
  - `KnownHostsCommand` - Execute command to obtain host keys dynamically (supports token substitution)
  - `ForkAfterAuthentication` - Fork SSH process to background after successful authentication (yes/no)
  - `SessionType` - Specify session type: none (port forwarding only), subsystem (e.g., SFTP), or default (shell)
  - `StdinNull` - Redirect stdin from /dev/null for background operations and scripting (yes/no)

- **SSH Configuration: Host Key Verification & Security Options**
  - `NoHostAuthenticationForLocalhost` - Skip host key verification for localhost connections (convenient for local development, default: no)
  - `HashKnownHosts` - Hash hostnames in known_hosts file to prevent hostname disclosure if compromised (default: no)
  - `CheckHostIP` - Check host IP address in known_hosts for DNS spoofing detection (deprecated in OpenSSH 8.5+, retained for legacy compatibility)
  - `VisualHostKey` - Display ASCII art of host key fingerprint for visual verification (default: no)
  - `HostKeyAlias` - Specify alias for host key lookup in known_hosts (useful for load-balanced services with shared keys)
  - `VerifyHostKeyDNS` - Verify host keys using DNS SSHFP records (yes/no/ask, default: no)
  - `UpdateHostKeys` - Accept updated host keys from server automatically (yes/no/ask, default: no)

- **SSH Configuration: Additional Authentication Options**
  - `NumberOfPasswordPrompts` - Control password authentication retry attempts (valid range: 1-10, default: 3)
  - `EnableSSHKeysign` - Enable ssh-keysign for host-based authentication (yes/no, default: no)

- **SSH Configuration: Network & Connection Options**
  - `BindInterface` - Bind SSH connection to specific network interface (alternative to BindAddress for multi-homed hosts)
  - `IPQoS` - Set IP type-of-service/DSCP values for interactive and bulk traffic (e.g., "lowdelay throughput")
  - `RekeyLimit` - Control SSH session key renegotiation frequency (format: "data [time]", e.g., "1G 1h")

- **SSH Configuration: X11 Forwarding Options**
  - `ForwardX11Timeout` - Set timeout for untrusted X11 forwarding connections (time interval, default: 0 = no timeout)
  - `ForwardX11Trusted` - Enable trusted X11 forwarding with full display access (yes/no, default: no)

- **Security Enhancements**
  - Path validation to prevent usage of sensitive system files (e.g., /etc/passwd, /etc/shadow)
  - Memory exhaustion prevention with entry limits for certificates and forwarding rules
  - Algorithm list validation with maximum entry limits
  - Deduplication for certificate files and remote forwarding destinations
  - Command injection prevention for LocalCommand and KnownHostsCommand
  - Token validation to prevent invalid substitution patterns
  - Dangerous character detection in command strings (semicolons, backticks, pipes, etc.)

### Changed
- **SSH Config Parser**: Refactored into modular structure for better maintainability
  - Split oversized parser.rs (1706 lines) into category-based modules (~200-350 lines each)
  - Organized option parsing by categories: authentication, security, forwarding, connection, etc.
  - Improved code organization and maintainability

### Technical Details
- Enhanced SSH configuration merging logic with proper priority handling
- Support for both "Option Value" and "Option=Value" syntax
- Scalar options override in later blocks, vector options accumulate with deduplication
- **SSH Configuration Coverage**: ~71 options (~69% of OpenSSH's 103 options)
  - Basic options + Include + Match directives (structural)
  - Certificate authentication and port forwarding (7 options)
  - Command execution and automation (7 options)
  - Host key verification, authentication, network, and X11 options (15 options)
- Comprehensive test coverage: 278 tests including parser, resolver, integration, and security tests
- Validation: NumberOfPasswordPrompts range checking (1-10), CheckHostIP deprecation warnings

## [0.9.1] - 2025-10-14

### Added
None

### Changed
- **PTY Terminal Modes**: Complete implementation of PTY terminal modes for better interactive session support
- **Shift Key Input Support**: Full Shift key input handling in PTY mode for proper terminal behavior

### Fixed
- Terminal mode implementation for PTY sessions
- Shift key input handling in interactive mode

### Technical Details
- Enhanced terminal mode settings for PTY allocation
- Implemented proper terminal flag handling for interactive sessions
- Improved keyboard input processing for special keys

## [0.9.0] - 2025-10-14

### Added
- **Configurable Jump Host Limit**: Maximum number of jump hosts can now be configured via environment variable
  - `BSSH_MAX_JUMP_HOSTS` environment variable for dynamic limit configuration
  - Default: 10 jump hosts, Absolute maximum: 30 (security cap)
  - Invalid/zero values fall back to default with warning logs
  - Example: `BSSH_MAX_JUMP_HOSTS=20 bssh -J host1,...,host20 target`
  - Prevents resource exhaustion attacks while allowing flexible configurations

- **Jump Host File Transfer Support**: Added complete file transfer operations through SSH jump hosts
  - `upload_file_with_jump_hosts()` - Upload single files through jump host chains
  - `download_file_with_jump_hosts()` - Download single files through jump hosts
  - `upload_dir_with_jump_hosts()` - Upload directories recursively through jump hosts
  - `download_dir_with_jump_hosts()` - Download directories through jump hosts
  - All file transfer operations now fully support multi-hop SSH connections

- **Jump Host Interactive Mode Support**: Interactive shell sessions now work through jump hosts
  - Added `jump_hosts` field to `InteractiveCommand` structure
  - Dynamic timeout calculation based on hop count (30s base + 15s per hop)
  - Prevents premature timeouts on multi-hop connections
  - Full authentication support (SSH keys, agent, password) for each hop

- **Parallel Executor Integration**: Jump host support across all parallel operations
  - Updated `executor.rs` to propagate jump_hosts to all node operations
  - Maintains backward compatibility with `Option<&str>` type
  - All `*_to_node()` functions now accept `jump_hosts` parameter

### Changed
- **Interactive Mode**: Now includes jump host support with automatic timeout adjustment
  - Connection timeout scales with hop count for reliability
  - Example timeouts: Direct (30s), 1 hop (45s), 2 hops (60s), 3 hops (75s)

- **Test Coverage**: Updated all test files to include jump_hosts parameter
  - `tests/interactive_test.rs`: Added `jump_hosts: None` to test cases
  - `tests/interactive_integration_test.rs`: Updated all 9 test instances
  - `examples/interactive_demo.rs`: Updated example with jump_hosts field

- **Dependencies**: Updated various dependencies for security patches and stability

### Fixed
- Interactive mode timeout issues when connecting through jump hosts
- File transfer operations not working with jump host chains

### Security
- Added `serial_test` dependency for thread-safe environment variable testing
- Comprehensive test coverage for environment variable functionality (6 new tests)

### Technical Details
- **Files Modified**: 8 files
- **Lines Added**: +623
- **Lines Removed**: -26
- **Net Change**: +597 lines
- **Test Results**: All 132 tests passing

## [0.8.0] - 2025-09-12

### Added
- Comprehensive SSH port forwarding support
  - Local port forwarding (`-L`) for tunneling to remote services
  - Remote port forwarding (`-R`) for exposing local services
  - Dynamic port forwarding (`-D`) for SOCKS4/5 proxy functionality
- Improved error messages with better context and recovery suggestions

### Changed
- Removed dangerous `unwrap()` calls throughout codebase
- Enhanced error handling with detailed failure reasons

## [0.7.0] - 2025-08-30

### Added
- SSH jump host infrastructure (`-J` option)
  - OpenSSH ProxyJump format parsing
  - Multiple jump hosts support (comma-separated)
  - IPv6 address handling with bracket notation
  - Jump host chain management and connection establishment

### Changed
- Improved Ubuntu PPA support with better packaging
- Fixed deprecated GitHub Actions workflows

## [0.6.1] - 2025-08-28

### Changed
- Rebranded from "Backend.AI SSH" to "Broadcast SSH"
  - Emphasizes core broadcast/parallel functionality
  - Better reflects the tool's primary purpose

## [0.6.0] - 2025-08-28

### Added
- SSH configuration file support (`-F` option)
  - Auto-loads from `~/.ssh/config` by default
  - Supports 40+ SSH directives
  - Wildcard pattern matching and negation
  - Environment variable expansion in paths
- PTY allocation for interactive sessions (`-t`/`-T` options)
- SSH configuration caching for improved performance
  - LRU cache with configurable size and TTL
  - File modification detection
  - 10-100x faster repeated operations

### Changed
- Enhanced security with improved host key verification
- Performance improvements across core operations
- SSH-compatible command-line interface (drop-in replacement)

## [0.5.4] - 2025-08-27

### Fixed
- Parallel configuration value handling issues
- Interactive mode authentication alignment with exec mode

## [0.5.3] - 2025-08-27

### Changed
- Backend.AI cluster auto-detection now uses cluster SSH key configuration

## [0.5.2] - 2025-08-27

### Fixed
- Configuration file loading priority issues
- Backend.AI environment variable handling improvements

### Changed
- Now uses cluster SSH key configuration when available

## [0.5.1] - 2025-08-25

### Added
- Configurable command timeout support
  - Set timeout via `--timeout` flag or configuration file
  - Support for unlimited execution time (`timeout=0`)
  - Default timeout: 300 seconds (5 minutes)

## [0.5.0] - 2025-08-22

### Added
- Interactive mode with PTY support
  - Single-node mode for focused interaction
  - Multiplex mode for parallel command execution
  - Node switching commands (`!node1`, `!node2`, etc.)
  - Broadcast command (`!broadcast <cmd>`)
  - Visual status indicators (● active, ○ inactive)
  - Command history with rustyline
  - Configurable prompts and settings

### Changed
- Improved Backend.AI cluster auto-detection
- Enhanced interactive shell capabilities

## [0.4.0] - 2025-08-22

### Added
- Password authentication support (`-P` flag)
- SSH key passphrase support with secure prompting
- Modern UI with semantic colors and Unicode symbols
- Debian package distribution (`.deb`)

### Changed
- XDG Base Directory specification compliance
- Improved configuration management
- Enhanced visual feedback and progress indicators

## [0.3.0] - 2025-08-22

### Added
- Native SFTP directory operations
- Recursive file transfer support
  - Upload directories with `-r` flag
  - Download entire directory trees
  - Glob pattern support for batch operations

## [0.2.0] - 2025-08-21

### Added
- Backend.AI multi-node session support
  - Automatic cluster detection from environment variables
  - Default SSH port 2200 for Backend.AI clusters
- SSH authentication enhancements
  - SSH agent authentication with auto-detection
  - Host key verification with known_hosts support
  - Multiple authentication method fallback
- Environment variable expansion in configuration files
- Connection and command timeout configuration
- SFTP file transfer (upload/download)
  - SCP-compatible file copy functionality
  - Progress tracking for file operations

### Changed
- Improved error messages and diagnostics
- Enhanced security with host key verification

## [0.1.0] - 2025-08-21

### Added
- Initial release of bssh
- Parallel SSH command execution across multiple nodes
- Cluster configuration management via YAML files
- Node specification via CLI (`-H` flag)
- SSH key-based authentication
- Real-time progress tracking with progress bars
- Per-node output collection and aggregation
- Configurable parallel execution limits
- Connectivity testing (`ping` command)
- Cluster listing (`list` command)

### Features
- Built with Rust for performance and safety
- Async/await pattern for maximum concurrency
- Tokio runtime for efficient I/O operations
- russh library for native SSH implementation
- Cross-platform support (Linux and macOS)

[2.1.2]: https://github.com/lablup/bssh/compare/v2.1.1...v2.1.2
[2.1.1]: https://github.com/lablup/bssh/compare/v2.1.0...v2.1.1
[2.1.0]: https://github.com/lablup/bssh/compare/v2.0.1...v2.1.0
[2.0.1]: https://github.com/lablup/bssh/compare/v2.0.0...v2.0.1
[2.0.0]: https://github.com/lablup/bssh/compare/v1.7.0...v2.0.0
[1.7.0]: https://github.com/lablup/bssh/compare/v1.6.0...v1.7.0
[1.6.0]: https://github.com/lablup/bssh/compare/v1.5.1...v1.6.0
[1.5.1]: https://github.com/lablup/bssh/compare/v1.5.0...v1.5.1
[1.5.0]: https://github.com/lablup/bssh/compare/v1.4.2...v1.5.0
[1.4.2]: https://github.com/lablup/bssh/compare/v1.4.1...v1.4.2
[1.4.1]: https://github.com/lablup/bssh/compare/v1.4.0...v1.4.1
[1.4.0]: https://github.com/lablup/bssh/compare/v1.3.0...v1.4.0
[1.3.0]: https://github.com/lablup/bssh/compare/v1.2.2...v1.3.0
[1.2.2]: https://github.com/lablup/bssh/compare/v1.2.1...v1.2.2
[1.2.1]: https://github.com/lablup/bssh/compare/v1.2.0...v1.2.1
[1.2.0]: https://github.com/lablup/bssh/compare/v1.1.0...v1.2.0
[1.1.0]: https://github.com/lablup/bssh/compare/v1.0.0...v1.1.0
[1.0.0]: https://github.com/lablup/bssh/compare/v0.9.1...v1.0.0
[0.9.1]: https://github.com/lablup/bssh/compare/v0.9.0...v0.9.1
[0.9.0]: https://github.com/lablup/bssh/compare/v0.8.0...v0.9.0
[0.8.0]: https://github.com/lablup/bssh/compare/v0.7.0...v0.8.0
[0.7.0]: https://github.com/lablup/bssh/compare/v0.6.1...v0.7.0
[0.6.1]: https://github.com/lablup/bssh/compare/v0.6.0...v0.6.1
[0.6.0]: https://github.com/lablup/bssh/compare/v0.5.4...v0.6.0
[0.5.4]: https://github.com/lablup/bssh/compare/v0.5.3...v0.5.4
[0.5.3]: https://github.com/lablup/bssh/compare/v0.5.2...v0.5.3
[0.5.2]: https://github.com/lablup/bssh/compare/v0.5.1...v0.5.2
[0.5.1]: https://github.com/lablup/bssh/compare/v0.5.0...v0.5.1
[0.5.0]: https://github.com/lablup/bssh/compare/v0.4.0...v0.5.0
[0.4.0]: https://github.com/lablup/bssh/compare/v0.3.0...v0.4.0
[0.3.0]: https://github.com/lablup/bssh/compare/v0.2.0...v0.3.0
[0.2.0]: https://github.com/lablup/bssh/compare/v0.1.0...v0.2.0
[0.1.0]: https://github.com/lablup/bssh/releases/tag/v0.1.0