Skip to main content

immutable_logging/
lib.rs

1//! Immutable Logging - Append-only audit logs with cryptographic proof
2//! 
3//! This module implements the immutable audit layer as specified in SPEC_IMMUTABLE_LOGGING.md
4//! Features:
5//! - Chained hash verification
6//! - Hourly Merkle tree roots
7//! - Daily publication
8//! - TSA timestamps
9
10pub mod log_entry;
11pub mod chain;
12pub mod merkle_service;
13pub mod publication;
14pub mod error;
15
16use serde::{Deserialize, Serialize};
17use std::sync::Arc;
18use tokio::sync::RwLock;
19
20/// Immutable log service
21pub struct ImmutableLog {
22    chain: Arc<RwLock<chain::LogChain>>,
23    merkle: Arc<RwLock<merkle_service::MerkleService>>,
24}
25
26impl ImmutableLog {
27    /// Create new immutable log
28    pub fn new() -> Self {
29        ImmutableLog {
30            chain: Arc::new(RwLock::new(chain::LogChain::new())),
31            merkle: Arc::new(RwLock::new(merkle_service::MerkleService::new())),
32        }
33    }
34    
35    /// Append a new entry
36    pub async fn append(&self, entry: log_entry::LogEntry) -> Result<log_entry::LogEntry, error::LogError> {
37        // Get current chain state
38        let mut chain = self.chain.write().await;
39        let entry = chain.append(entry).await?;
40        
41        // Add to merkle tree
42        let mut merkle = self.merkle.write().await;
43        merkle.add_entry(entry.clone()).await;
44        
45        Ok(entry)
46    }
47    
48    /// Verify chain integrity
49    pub async fn verify(&self) -> Result<bool, error::LogError> {
50        let chain = self.chain.read().await;
51        Ok(chain.verify())
52    }
53    
54    /// Get current hourly root
55    pub async fn get_hourly_root(&self) -> Option<merkle_service::HourlyRoot> {
56        let merkle = self.merkle.read().await;
57        merkle.get_current_root()
58    }
59    
60    /// Generate chain proof for an entry
61    pub async fn get_chain_proof(&self, entry_id: &str) -> Option<chain::ChainProof> {
62        let chain = self.chain.read().await;
63        chain.generate_proof(entry_id)
64    }
65}
66
67impl Default for ImmutableLog {
68    fn default() -> Self {
69        Self::new()
70    }
71}
72
73/// Configuration for immutable logging
74#[derive(Debug, Clone, Serialize, Deserialize)]
75pub struct LogConfig {
76    /// Hash algorithm
77    pub hash_algorithm: String,
78    /// Hourly publication enabled
79    pub hourly_publication: bool,
80    /// Daily publication enabled
81    pub daily_publication: bool,
82    /// TSA server URL
83    pub tsa_url: Option<String>,
84    /// Blockchain enabled
85    pub blockchain_enabled: bool,
86}
87
88impl Default for LogConfig {
89    fn default() -> Self {
90        LogConfig {
91            hash_algorithm: "SHA256".to_string(),
92            hourly_publication: true,
93            daily_publication: true,
94            tsa_url: None,
95            blockchain_enabled: true,
96        }
97    }
98}
99
100#[cfg(test)]
101mod tests {
102    use super::*;
103    
104    #[test]
105    fn test_default_config() {
106        let config = LogConfig::default();
107        assert_eq!(config.hash_algorithm, "SHA256");
108        assert!(config.hourly_publication);
109    }
110    
111    #[tokio::test]
112    async fn test_append_entry() {
113        let log = ImmutableLog::new();
114        
115        let entry = log_entry::LogEntry::new(
116            log_entry::EventType::AccountQuery,
117            "agent-001".to_string(),
118            "org-001".to_string(),
119        );
120        
121        let result = log.append(entry).await;
122        assert!(result.is_ok());
123    }
124}