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
//! SSH handler trait for pluggable transport implementations.
//!
//! Embedders can implement [`SshHandler`] to intercept, proxy, log,
//! or mock SSH operations. The allowlist check happens _before_ the
//! handler is called, so the security boundary stays in bashkit.
//!
//! # Default
//!
//! When no custom handler is set, `SshClient` uses `russh` directly.
use async_trait;
/// Connection target for an SSH operation.
///
/// Fully resolved by the builtin before passing to the handler.
/// The handler does NOT need to validate the host — that's already done.
/// Output from a remote command execution.
/// Trait for custom SSH transport implementations.
///
/// Embedders can implement this to:
/// - Mock SSH for testing
/// - Proxy through a bastion host
/// - Log/audit all SSH operations
/// - Rate-limit connections
///
/// The allowlist check happens _before_ the handler is called.
///
/// # Example
///
/// ```rust,ignore
/// use bashkit::ssh::{SshHandler, SshTarget, SshOutput};
/// use async_trait::async_trait;
///
/// struct MockSsh;
///
/// #[async_trait]
/// impl SshHandler for MockSsh {
/// async fn exec(
/// &self,
/// target: &SshTarget,
/// command: &str,
/// ) -> Result<SshOutput, String> {
/// Ok(SshOutput {
/// stdout: format!("mock: ran '{}' on {}\n", command, target.host),
/// stderr: String::new(),
/// exit_code: 0,
/// })
/// }
///
/// async fn upload(
/// &self, _target: &SshTarget, _remote_path: &str,
/// _content: &[u8], _mode: u32,
/// ) -> Result<(), String> {
/// Ok(())
/// }
///
/// async fn download(
/// &self, _target: &SshTarget, _remote_path: &str,
/// ) -> Result<Vec<u8>, String> {
/// Ok(Vec::new())
/// }
/// }
/// ```