Skip to main content

auths_core/ports/
ssh_agent.rs

1//! Port trait for system SSH agent key registration.
2
3use std::path::Path;
4
5/// Domain error for system SSH agent operations.
6///
7/// Args:
8/// * `CommandFailed` — The ssh-add command ran but returned a non-zero exit code.
9/// * `NotAvailable` — The SSH agent is not running or cannot be reached.
10/// * `IoError` — A filesystem or process I/O error occurred.
11///
12/// Usage:
13/// ```ignore
14/// use auths_core::ports::ssh_agent::SshAgentError;
15///
16/// fn handle(err: SshAgentError) {
17///     match err {
18///         SshAgentError::CommandFailed(msg) => eprintln!("ssh-add failed: {msg}"),
19///         SshAgentError::NotAvailable(msg) => eprintln!("agent unavailable: {msg}"),
20///         SshAgentError::IoError(msg) => eprintln!("I/O error: {msg}"),
21///     }
22/// }
23/// ```
24#[derive(Debug, thiserror::Error)]
25#[non_exhaustive]
26pub enum SshAgentError {
27    /// The ssh-add command ran but returned a failure status.
28    #[error("ssh-add command failed: {0}")]
29    CommandFailed(String),
30
31    /// The system SSH agent is not available.
32    #[error("SSH agent not available: {0}")]
33    NotAvailable(String),
34
35    /// A filesystem or process I/O error.
36    #[error("I/O error: {0}")]
37    IoError(String),
38}
39
40impl auths_crypto::AuthsErrorInfo for SshAgentError {
41    fn error_code(&self) -> &'static str {
42        match self {
43            Self::CommandFailed(_) => "AUTHS-E3901",
44            Self::NotAvailable(_) => "AUTHS-E3902",
45            Self::IoError(_) => "AUTHS-E3903",
46        }
47    }
48
49    fn suggestion(&self) -> Option<&'static str> {
50        match self {
51            Self::NotAvailable(_) => Some("Start the SSH agent: eval $(ssh-agent -s)"),
52            Self::CommandFailed(_) => {
53                Some("Check that the key file exists and has correct permissions")
54            }
55            Self::IoError(_) => Some("Check file permissions"),
56        }
57    }
58}
59
60/// Registers key files with the system SSH agent.
61///
62/// Implementations wrap platform-specific mechanisms (e.g., `ssh-add` on
63/// macOS/Linux). Domain code calls this trait without knowing the transport.
64///
65/// Usage:
66/// ```ignore
67/// use auths_core::ports::ssh_agent::SshAgentPort;
68///
69/// fn register(agent: &dyn SshAgentPort, key_path: &Path) {
70///     agent.register_key(key_path).unwrap();
71/// }
72/// ```
73pub trait SshAgentPort: Send + Sync {
74    /// Registers a PEM key file with the system SSH agent.
75    ///
76    /// Args:
77    /// * `key_path`: Path to a temporary PEM file to add via ssh-add.
78    ///
79    /// Usage:
80    /// ```ignore
81    /// agent.register_key(Path::new("/tmp/auths-key-abc.pem"))?;
82    /// ```
83    fn register_key(&self, key_path: &Path) -> Result<(), SshAgentError>;
84}