Skip to content
Clone
563bb99
101 lines 3.6 KB Rust
use serde::Deserialize;
#[derive(Clone, Debug, Deserialize)]
#[serde(default)]
pub struct CiConfig {
pub enabled: bool,
pub secret_encryption_key: String,
pub event_queue_topic: String,
pub event_dlq_topic: String,
pub lease_secs: u64,
pub heartbeat_interval_secs: u64,
pub long_poll_timeout_secs: u64,
pub max_attempts: i32,
pub job_timeout_default_secs: u64,
pub job_timeout_max_secs: u64,
pub log_chunk_max_bytes: u64,
pub log_retention_days: i64,
pub artifact_retention_days: i64,
pub run_retention_days: i64,
pub artifact_max_bytes: u64,
pub outbound_max_attempts: i32,
pub outbound_backoff_base_secs: i64,
pub outbound_timeout_secs: u64,
pub scheduler_interval_secs: u64,
pub cancel_grace_secs: u64,
}
impl Default for CiConfig {
fn default() -> Self {
Self {
enabled: false,
secret_encryption_key: String::new(),
event_queue_topic: "gitdata:events".to_string(),
event_dlq_topic: "gitdata:events:dlq".to_string(),
lease_secs: 60,
heartbeat_interval_secs: 15,
long_poll_timeout_secs: 30,
max_attempts: 2,
job_timeout_default_secs: 3600,
job_timeout_max_secs: 21600,
log_chunk_max_bytes: 262_144,
log_retention_days: 30,
artifact_retention_days: 30,
run_retention_days: 180,
artifact_max_bytes: 2 * 1024 * 1024 * 1024,
outbound_max_attempts: 5,
outbound_backoff_base_secs: 60,
outbound_timeout_secs: 10,
scheduler_interval_secs: 2,
cancel_grace_secs: 120,
}
}
}
impl CiConfig {
pub fn validate(&self) -> Result<(), String> {
if !self.enabled {
return Ok(());
}
if self.secret_encryption_key.trim().is_empty() {
return Err(
"ci.secret_encryption_key must not be empty when ci is enabled".to_string(),
);
}
let decoded = base64::Engine::decode(
&base64::engine::general_purpose::STANDARD,
self.secret_encryption_key.trim(),
)
.map_err(|_| "ci.secret_encryption_key must be base64".to_string())?;
if decoded.len() < 32 {
return Err("ci.secret_encryption_key must decode to at least 32 bytes".to_string());
}
if self.event_queue_topic.trim().is_empty() || self.event_dlq_topic.trim().is_empty() {
return Err("ci event topics must not be empty".to_string());
}
if self.lease_secs == 0
|| self.heartbeat_interval_secs == 0
|| self.long_poll_timeout_secs == 0
|| self.job_timeout_default_secs == 0
|| self.job_timeout_max_secs == 0
|| self.job_timeout_max_secs < self.job_timeout_default_secs
|| self.log_chunk_max_bytes == 0
|| self.scheduler_interval_secs == 0
{
return Err("ci timing and size limits must be greater than zero".to_string());
}
if self.max_attempts <= 0 || self.outbound_max_attempts <= 0 {
return Err("ci attempt limits must be greater than zero".to_string());
}
if self.log_retention_days < 0
|| self.artifact_retention_days < 0
|| self.run_retention_days < 0
{
return Err("ci retention days must not be negative".to_string());
}
if self.heartbeat_interval_secs >= self.lease_secs {
return Err("ci.heartbeat_interval_secs must be less than ci.lease_secs".to_string());
}
Ok(())
}
}