1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
//! Risk review scheduler for automated risk review execution
//!
//! This module provides a scheduler that automatically reviews risks
//! based on their review frequency and schedules.
use crate::security::risk_assessment::RiskAssessmentEngine;
use std::sync::Arc;
use tokio::sync::RwLock;
use tokio::time::{interval, Duration as TokioDuration};
use tracing::{debug, error, info};
/// Risk review scheduler
///
/// This scheduler automatically reviews risks based on their configured
/// review frequencies. It checks for due reviews periodically and reviews them.
pub struct RiskReviewScheduler {
engine: Arc<RwLock<RiskAssessmentEngine>>,
/// Whether the scheduler is running
running: Arc<RwLock<bool>>,
/// System user ID for automated reviews
system_user_id: uuid::Uuid,
}
impl RiskReviewScheduler {
/// Create a new risk review scheduler
pub fn new(engine: Arc<RwLock<RiskAssessmentEngine>>) -> Self {
Self {
engine,
running: Arc::new(RwLock::new(false)),
// Use a fixed system UUID for automated reviews
system_user_id: uuid::Uuid::parse_str("00000000-0000-0000-0000-000000000001")
.expect("Invalid system UUID"),
}
}
/// Start the risk review scheduler
///
/// This spawns a background task that periodically checks for risks
/// due for review and automatically reviews them.
pub fn start(&self) -> tokio::task::JoinHandle<()> {
let engine = self.engine.clone();
let running = self.running.clone();
let system_user_id = self.system_user_id;
tokio::spawn(async move {
// Mark as running before entering the loop
*running.write().await = true;
// Check every 6 hours for due reviews
let mut interval = interval(TokioDuration::from_secs(6 * 3600));
loop {
interval.tick().await;
// Check if still running
if !*running.read().await {
debug!("Risk review scheduler stopped");
break;
}
// Get risks due for review
let risks_due = {
let engine_guard = engine.read().await;
match engine_guard.get_risks_due_for_review().await {
Ok(risks) => risks,
Err(e) => {
error!("Failed to get risks due for review: {}", e);
continue;
}
}
};
if risks_due.is_empty() {
debug!("No risks due for review");
continue;
}
info!(
"Found {} risk(s) due for review, starting automated review",
risks_due.len()
);
// Review each risk
for risk in risks_due {
let risk_id = risk.risk_id.clone();
let engine_guard = engine.write().await;
match engine_guard.review_risk(&risk_id, system_user_id).await {
Ok(()) => {
info!("Automated review completed for risk {}", risk_id);
}
Err(e) => {
error!("Failed to review risk {}: {}", risk_id, e);
}
}
}
}
})
}
/// Stop the risk review scheduler
pub async fn stop(&self) {
let mut running = self.running.write().await;
*running = false;
info!("Risk review scheduler stopping...");
}
/// Check if the scheduler is running
pub async fn is_running(&self) -> bool {
*self.running.read().await
}
}