mirror of
https://github.com/outbackdingo/optimclaw.git
synced 2026-08-26 23:50:17 +00:00
feat: add background sandbox reaper for orphaned Docker containers (#634)
* feat: add background sandbox reaper for orphaned Docker containers * add tests * review fixes * linter fix * review fixes * style: format test assertion in reaper Apply rustfmt to improve code formatting consistency. Co-Authored-By: Claude Haiku 4.5 <[email protected]> * fix: revert assertion to single-line format for CI compatibility The assertion should remain on a single line to match CI's rustfmt expectations. Co-Authored-By: Claude Haiku 4.5 <[email protected]> * fix: format assertion to multi-line for CI rustfmt Use multi-line format for the assert macro to comply with CI's rustfmt line length limit (100 chars). Co-Authored-By: Claude Haiku 4.5 <[email protected]> --------- Co-authored-by: Claude Haiku 4.5 <[email protected]>
This commit is contained in:
co-authored by
Claude Haiku 4.5
parent
fcb152e408
commit
45923ef360
@@ -20,6 +20,10 @@ pub struct SandboxModeConfig {
|
||||
pub auto_pull_image: bool,
|
||||
/// Additional domains to allow through the network proxy.
|
||||
pub extra_allowed_domains: Vec<String>,
|
||||
/// How often the reaper scans for orphaned containers (seconds). Default: 300 (5 min).
|
||||
pub reaper_interval_secs: u64,
|
||||
/// Containers older than this with no active job are reaped (seconds). Default: 600 (10 min).
|
||||
pub orphan_threshold_secs: u64,
|
||||
}
|
||||
|
||||
impl Default for SandboxModeConfig {
|
||||
@@ -33,6 +37,8 @@ impl Default for SandboxModeConfig {
|
||||
image: "ironclaw-worker:latest".to_string(),
|
||||
auto_pull_image: true,
|
||||
extra_allowed_domains: Vec::new(),
|
||||
reaper_interval_secs: 300,
|
||||
orphan_threshold_secs: 600,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -43,6 +49,24 @@ impl SandboxModeConfig {
|
||||
.map(|s| s.split(',').map(|d| d.trim().to_string()).collect())
|
||||
.unwrap_or_default();
|
||||
|
||||
let reaper_interval_secs: u64 = parse_optional_env("SANDBOX_REAPER_INTERVAL_SECS", 300)?;
|
||||
let orphan_threshold_secs: u64 = parse_optional_env("SANDBOX_ORPHAN_THRESHOLD_SECS", 600)?;
|
||||
|
||||
// Validate that reaper timings are non-zero to prevent tokio::time::interval panics
|
||||
if reaper_interval_secs == 0 {
|
||||
return Err(ConfigError::InvalidValue {
|
||||
key: "SANDBOX_REAPER_INTERVAL_SECS".to_string(),
|
||||
message: "must be greater than 0".to_string(),
|
||||
});
|
||||
}
|
||||
|
||||
if orphan_threshold_secs == 0 {
|
||||
return Err(ConfigError::InvalidValue {
|
||||
key: "SANDBOX_ORPHAN_THRESHOLD_SECS".to_string(),
|
||||
message: "must be greater than 0".to_string(),
|
||||
});
|
||||
}
|
||||
|
||||
Ok(Self {
|
||||
enabled: parse_bool_env("SANDBOX_ENABLED", true)?,
|
||||
policy: parse_string_env("SANDBOX_POLICY", "readonly")?,
|
||||
@@ -52,6 +76,8 @@ impl SandboxModeConfig {
|
||||
image: parse_string_env("SANDBOX_IMAGE", "ironclaw-worker:latest")?,
|
||||
auto_pull_image: parse_bool_env("SANDBOX_AUTO_PULL", true)?,
|
||||
extra_allowed_domains: extra_domains,
|
||||
reaper_interval_secs,
|
||||
orphan_threshold_secs,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -273,6 +299,8 @@ mod tests {
|
||||
image: "custom-worker:v2".to_string(),
|
||||
auto_pull_image: false,
|
||||
extra_allowed_domains: vec!["example.com".to_string()],
|
||||
reaper_interval_secs: 300,
|
||||
orphan_threshold_secs: 600,
|
||||
};
|
||||
assert!(!cfg.enabled);
|
||||
assert_eq!(cfg.policy, "full_access");
|
||||
@@ -295,6 +323,8 @@ mod tests {
|
||||
image: "test:latest".to_string(),
|
||||
auto_pull_image: false,
|
||||
extra_allowed_domains: vec!["custom.example.com".to_string()],
|
||||
reaper_interval_secs: 300,
|
||||
orphan_threshold_secs: 600,
|
||||
};
|
||||
let sc = mode.to_sandbox_config();
|
||||
assert!(sc.enabled);
|
||||
|
||||
Reference in New Issue
Block a user