Skip to main content

auths_sdk/ports/
git.rs

1//! Git log provider port for audit and compliance workflows.
2//!
3//! Defines the trait boundary for reading commit history.
4//! Production adapters (e.g. git2-based) live in infra crates.
5
6/// A single commit record from the repository history.
7///
8/// Args:
9/// * `hash`: The abbreviated commit hash.
10/// * `author_name`: The commit author's name.
11/// * `author_email`: The commit author's email.
12/// * `timestamp`: ISO-8601 formatted commit timestamp.
13/// * `message`: First line of the commit message.
14/// * `signature_status`: Classification of the commit's signature.
15///
16/// Usage:
17/// ```ignore
18/// let record = CommitRecord {
19///     hash: "abc1234".to_string(),
20///     author_name: "Alice".to_string(),
21///     author_email: "alice@example.com".to_string(),
22///     timestamp: "2024-01-15T10:00:00Z".to_string(),
23///     message: "initial commit".to_string(),
24///     signature_status: SignatureStatus::Unsigned,
25/// };
26/// ```
27#[derive(Debug, Clone)]
28pub struct CommitRecord {
29    /// The abbreviated commit hash.
30    pub hash: String,
31    /// The commit author's name.
32    pub author_name: String,
33    /// The commit author's email.
34    pub author_email: String,
35    /// ISO-8601 formatted commit timestamp.
36    pub timestamp: String,
37    /// First line of the commit message.
38    pub message: String,
39    /// Classification of the commit's signature.
40    pub signature_status: SignatureStatus,
41}
42
43/// Classification of a commit's cryptographic signature.
44///
45/// Usage:
46/// ```ignore
47/// match status {
48///     SignatureStatus::AuthsSigned { signer_did } => println!("Signed by {signer_did}"),
49///     SignatureStatus::SshSigned => println!("SSH signed"),
50///     SignatureStatus::GpgSigned { verified } => println!("GPG signed, verified={verified}"),
51///     SignatureStatus::Unsigned => println!("No signature"),
52///     SignatureStatus::InvalidSignature { reason } => println!("Bad sig: {reason}"),
53/// }
54/// ```
55#[derive(Debug, Clone)]
56pub enum SignatureStatus {
57    /// Signed using the auths workflow.
58    AuthsSigned {
59        /// The DID of the signer.
60        signer_did: String,
61    },
62    /// Signed using SSH.
63    SshSigned,
64    /// Signed using GPG.
65    GpgSigned {
66        /// Whether the GPG signature was verified.
67        verified: bool,
68    },
69    /// No signature present.
70    Unsigned,
71    /// A signature was present but invalid.
72    InvalidSignature {
73        /// The reason the signature is invalid.
74        reason: String,
75    },
76}
77
78/// Errors from git log provider operations.
79#[derive(Debug, thiserror::Error)]
80pub enum GitProviderError {
81    /// Failed to open the git repository.
82    #[error("failed to open repository: {0}")]
83    Open(String),
84    /// Failed to walk the commit history.
85    #[error("failed to walk commits: {0}")]
86    Walk(String),
87    /// An object ID could not be parsed.
88    #[error("invalid oid: {0}")]
89    InvalidOid(String),
90    /// The requested commit was not found.
91    #[error("commit not found: {0}")]
92    NotFound(String),
93    /// The repository lock was poisoned by a panicking thread.
94    #[error("repository lock poisoned")]
95    LockPoisoned,
96}
97
98/// Port for reading commit history from a Git repository.
99///
100/// Usage:
101/// ```ignore
102/// let commits: Vec<CommitRecord> = provider
103///     .walk_commits(None, Some(100))?
104///     .collect::<Result<Vec<_>, _>>()?;
105/// ```
106pub trait GitLogProvider: Send + Sync {
107    /// Walk commit history, optionally constrained by a range spec and limit.
108    ///
109    /// Args:
110    /// * `range`: Optional git revision range (e.g. "HEAD~10..HEAD").
111    /// * `limit`: Optional maximum number of commits to return.
112    fn walk_commits(
113        &self,
114        range: Option<&str>,
115        limit: Option<usize>,
116    ) -> Result<Vec<CommitRecord>, GitProviderError>;
117}