Files
compliance-scanner-agent/compliance-agent/src/scheduler.rs
Sharang Parnerkar 03ee69834d
All checks were successful
CI / Format (push) Successful in 3s
CI / Clippy (push) Successful in 2m15s
CI / Security Audit (push) Successful in 1m34s
CI / Tests (push) Successful in 3m4s
Fix formatting and clippy warnings across workspace
- Run cargo fmt on all crates
- Fix regex patterns using unsupported lookahead in patterns.rs
- Replace unwrap() calls with compile_regex() helper
- Fix never type fallback in GitHub tracker
- Fix redundant field name in findings page
- Allow enum_variant_names for Dioxus Route enum
- Fix &mut Vec -> &mut [T] clippy lint in sbom.rs
- Mark unused-but-intended APIs with #[allow(dead_code)]

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 17:41:03 +01:00

106 lines
3.4 KiB
Rust

use mongodb::bson::doc;
use tokio_cron_scheduler::{Job, JobScheduler};
use compliance_core::models::ScanTrigger;
use crate::agent::ComplianceAgent;
use crate::error::AgentError;
pub async fn start_scheduler(agent: &ComplianceAgent) -> Result<(), AgentError> {
let sched = JobScheduler::new()
.await
.map_err(|e| AgentError::Scheduler(format!("Failed to create scheduler: {e}")))?;
// Periodic scan job
let scan_agent = agent.clone();
let scan_schedule = agent.config.scan_schedule.clone();
let scan_job = Job::new_async(scan_schedule.as_str(), move |_uuid, _lock| {
let agent = scan_agent.clone();
Box::pin(async move {
tracing::info!("Scheduled scan triggered");
scan_all_repos(&agent).await;
})
})
.map_err(|e| AgentError::Scheduler(format!("Failed to create scan job: {e}")))?;
sched
.add(scan_job)
.await
.map_err(|e| AgentError::Scheduler(format!("Failed to add scan job: {e}")))?;
// CVE monitor job (daily)
let cve_agent = agent.clone();
let cve_schedule = agent.config.cve_monitor_schedule.clone();
let cve_job = Job::new_async(cve_schedule.as_str(), move |_uuid, _lock| {
let agent = cve_agent.clone();
Box::pin(async move {
tracing::info!("CVE monitor triggered");
monitor_cves(&agent).await;
})
})
.map_err(|e| AgentError::Scheduler(format!("Failed to create CVE monitor job: {e}")))?;
sched
.add(cve_job)
.await
.map_err(|e| AgentError::Scheduler(format!("Failed to add CVE monitor job: {e}")))?;
sched
.start()
.await
.map_err(|e| AgentError::Scheduler(format!("Failed to start scheduler: {e}")))?;
tracing::info!(
"Scheduler started: scans='{}', CVE monitor='{}'",
agent.config.scan_schedule,
agent.config.cve_monitor_schedule,
);
// Keep scheduler alive
loop {
tokio::time::sleep(tokio::time::Duration::from_secs(3600)).await;
}
}
async fn scan_all_repos(agent: &ComplianceAgent) {
use futures_util::StreamExt;
let cursor = match agent.db.repositories().find(doc! {}).await {
Ok(c) => c,
Err(e) => {
tracing::error!("Failed to list repos for scheduled scan: {e}");
return;
}
};
let repos: Vec<_> = cursor.filter_map(|r| async { r.ok() }).collect().await;
for repo in repos {
let repo_id = repo.id.map(|id| id.to_hex()).unwrap_or_default();
if let Err(e) = agent.run_scan(&repo_id, ScanTrigger::Scheduled).await {
tracing::error!("Scheduled scan failed for {}: {e}", repo.name);
}
}
}
async fn monitor_cves(agent: &ComplianceAgent) {
use futures_util::StreamExt;
// Re-scan all SBOM entries for new CVEs
let cursor = match agent.db.sbom_entries().find(doc! {}).await {
Ok(c) => c,
Err(e) => {
tracing::error!("Failed to list SBOM entries for CVE monitoring: {e}");
return;
}
};
let entries: Vec<_> = cursor.filter_map(|r| async { r.ok() }).collect().await;
if entries.is_empty() {
return;
}
tracing::info!("CVE monitor: checking {} dependencies", entries.len());
// The actual CVE checking is handled by the CveScanner in the pipeline
// This is a simplified version that just logs the activity
}