use crate::ports::git::{CommitRecord, GitLogProvider, GitProviderError, SignatureStatus};
use serde::{Deserialize, Serialize};
#[derive(Debug, thiserror::Error)]
pub enum AuditError {
#[error("git provider error: {0}")]
Provider(#[from] GitProviderError),
}
#[derive(Debug)]
pub struct AuditReport {
pub commits: Vec<CommitRecord>,
pub summary: AuditSummary,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AuditSummary {
pub total_commits: usize,
pub signed_commits: usize,
pub unsigned_commits: usize,
pub auths_signed: usize,
pub gpg_signed: usize,
pub ssh_signed: usize,
pub verification_passed: usize,
pub verification_failed: usize,
}
pub struct AuditWorkflow<'a, G: GitLogProvider> {
provider: &'a G,
}
impl<'a, G: GitLogProvider> AuditWorkflow<'a, G> {
pub fn new(provider: &'a G) -> Self {
Self { provider }
}
pub fn generate_report(
&self,
range: Option<&str>,
limit: Option<usize>,
) -> Result<AuditReport, AuditError> {
let commits = self.provider.walk_commits(range, limit)?;
let summary = summarize_commits(&commits);
Ok(AuditReport { commits, summary })
}
}
pub fn summarize_commits(commits: &[CommitRecord]) -> AuditSummary {
let total_commits = commits.len();
let mut signed_commits = 0usize;
let mut auths_signed = 0usize;
let mut gpg_signed = 0usize;
let mut ssh_signed = 0usize;
let mut verification_passed = 0usize;
for c in commits {
match &c.signature_status {
SignatureStatus::AuthsSigned { .. } => {
signed_commits += 1;
auths_signed += 1;
verification_passed += 1;
}
SignatureStatus::SshSigned => {
signed_commits += 1;
ssh_signed += 1;
}
SignatureStatus::GpgSigned { verified } => {
signed_commits += 1;
gpg_signed += 1;
if *verified {
verification_passed += 1;
}
}
SignatureStatus::InvalidSignature { .. } => {
signed_commits += 1;
}
SignatureStatus::Unsigned => {}
}
}
AuditSummary {
total_commits,
unsigned_commits: total_commits - signed_commits,
verification_failed: signed_commits - verification_passed,
signed_commits,
auths_signed,
gpg_signed,
ssh_signed,
verification_passed,
}
}