Skip to main content

auths_sdk/ports/
diagnostics.rs

1//! Diagnostic provider ports for system health checks.
2//!
3//! Follows Interface Segregation: one trait per tool category so tests
4//! only mock what they need.
5
6use serde::{Deserialize, Serialize};
7
8/// A structured issue found during git signing configuration checks.
9#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
10pub enum ConfigIssue {
11    /// A key exists but has the wrong value.
12    Mismatch {
13        /// The git config key name.
14        key: String,
15        /// The expected value.
16        expected: String,
17        /// The actual value found.
18        actual: String,
19    },
20    /// A required key is not set.
21    Absent(String),
22}
23
24/// Result of a single diagnostic check.
25#[derive(Debug, Clone, Serialize, Deserialize)]
26pub struct CheckResult {
27    /// Human-readable name of the diagnostic check.
28    pub name: String,
29    /// Whether the check passed.
30    pub passed: bool,
31    /// Free-form informational text (e.g. version strings).
32    pub message: Option<String>,
33    /// Structured config issues — populated only by config checks.
34    #[serde(default)]
35    pub config_issues: Vec<ConfigIssue>,
36}
37
38/// Aggregated diagnostic report.
39#[derive(Debug, Serialize, Deserialize)]
40pub struct DiagnosticReport {
41    /// All individual check results in the report.
42    pub checks: Vec<CheckResult>,
43}
44
45/// Errors from diagnostic check execution.
46#[derive(Debug, thiserror::Error)]
47pub enum DiagnosticError {
48    /// A diagnostic check failed to execute.
49    #[error("check failed to execute: {0}")]
50    ExecutionFailed(String),
51}
52
53/// Port for Git-related diagnostic checks.
54///
55/// Usage:
56/// ```ignore
57/// let result = provider.check_git_version()?;
58/// let config_val = provider.get_git_config("user.email")?;
59/// ```
60pub trait GitDiagnosticProvider: Send + Sync {
61    /// Check that git is installed and return version info.
62    fn check_git_version(&self) -> Result<CheckResult, DiagnosticError>;
63
64    /// Read a global git config value, returning `None` if unset.
65    fn get_git_config(&self, key: &str) -> Result<Option<String>, DiagnosticError>;
66}
67
68/// Port for cryptographic tool diagnostic checks.
69///
70/// Usage:
71/// ```ignore
72/// let result = provider.check_ssh_keygen_available()?;
73/// ```
74pub trait CryptoDiagnosticProvider: Send + Sync {
75    /// Check that ssh-keygen is available on the system.
76    fn check_ssh_keygen_available(&self) -> Result<CheckResult, DiagnosticError>;
77}
78
79impl<T: GitDiagnosticProvider> GitDiagnosticProvider for &T {
80    fn check_git_version(&self) -> Result<CheckResult, DiagnosticError> {
81        (**self).check_git_version()
82    }
83    fn get_git_config(&self, key: &str) -> Result<Option<String>, DiagnosticError> {
84        (**self).get_git_config(key)
85    }
86}
87
88impl<T: CryptoDiagnosticProvider> CryptoDiagnosticProvider for &T {
89    fn check_ssh_keygen_available(&self) -> Result<CheckResult, DiagnosticError> {
90        (**self).check_ssh_keygen_available()
91    }
92}