use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum CheckCategory {
Critical,
Advisory,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum ConfigIssue {
Mismatch {
key: String,
expected: String,
actual: String,
},
Absent(String),
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CheckResult {
pub name: String,
pub passed: bool,
pub message: Option<String>,
#[serde(default)]
pub config_issues: Vec<ConfigIssue>,
#[serde(default = "default_check_category")]
pub category: CheckCategory,
}
fn default_check_category() -> CheckCategory {
CheckCategory::Advisory
}
#[derive(Debug, Serialize, Deserialize)]
pub struct DiagnosticReport {
pub checks: Vec<CheckResult>,
}
#[derive(Debug, thiserror::Error)]
pub enum DiagnosticError {
#[error("check failed to execute: {0}")]
ExecutionFailed(String),
#[error("check not found: {0}")]
CheckNotFound(String),
}
pub trait GitDiagnosticProvider: Send + Sync {
fn check_git_version(&self) -> Result<CheckResult, DiagnosticError>;
fn get_git_config(&self, key: &str) -> Result<Option<String>, DiagnosticError>;
}
pub trait CryptoDiagnosticProvider: Send + Sync {
fn check_ssh_keygen_available(&self) -> Result<CheckResult, DiagnosticError>;
fn check_ssh_version(&self) -> Result<String, DiagnosticError> {
Ok("unknown".to_string())
}
}
impl<T: GitDiagnosticProvider> GitDiagnosticProvider for &T {
fn check_git_version(&self) -> Result<CheckResult, DiagnosticError> {
(**self).check_git_version()
}
fn get_git_config(&self, key: &str) -> Result<Option<String>, DiagnosticError> {
(**self).get_git_config(key)
}
}
pub trait DiagnosticFix: Send + Sync {
fn name(&self) -> &str;
fn is_safe(&self) -> bool;
fn can_fix(&self, check: &CheckResult) -> bool;
fn apply(&self) -> Result<String, DiagnosticError>;
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FixApplied {
pub name: String,
pub message: String,
}
impl<T: CryptoDiagnosticProvider> CryptoDiagnosticProvider for &T {
fn check_ssh_keygen_available(&self) -> Result<CheckResult, DiagnosticError> {
(**self).check_ssh_keygen_available()
}
fn check_ssh_version(&self) -> Result<String, DiagnosticError> {
(**self).check_ssh_version()
}
}