fix7: продакшен-реализация полного reconcile swap и интеграций
- Полностью переписан swap-модуль в режиме exclusive ownership\n- Добавлены verify/checks, статус фактического swap-state и drift\n- Интегрирован ensure-swap в daemon и systemd ExecStartPre\n- Усилен lock API (таймауты) и применение в traffic/firewall/swap\n- Усилен parser firewall (JSON-first + устойчивый text fallback)\n- Обновлены config validation, runtime tools и default priority\n- Синхронизированы docs и build/package hygiene\n- Удалены member Cargo.lock в пользу корневого lockfile
This commit is contained in:
@@ -95,12 +95,22 @@ impl Config {
|
||||
anyhow::bail!("traffic.reconcile_interval_secs must be > 0");
|
||||
}
|
||||
if self.swap.enabled {
|
||||
if self.swap.size_mb == 0 {
|
||||
anyhow::bail!("swap.size_mb must be > 0 when swap.enabled=true");
|
||||
if self.swap.size_mb < 64 {
|
||||
anyhow::bail!("swap.size_mb must be >= 64 when swap.enabled=true");
|
||||
}
|
||||
if self.swap.size_mb > 65536 {
|
||||
anyhow::bail!("swap.size_mb must be <= 65536 when swap.enabled=true");
|
||||
}
|
||||
if !self.swap.path.starts_with('/') {
|
||||
anyhow::bail!("swap.path must be absolute");
|
||||
}
|
||||
let dangerous = ["/", "/etc", "/etc/fstab", "/dev", "/proc", "/sys", "/run"];
|
||||
if dangerous.iter().any(|p| *p == self.swap.path) {
|
||||
anyhow::bail!("swap.path is dangerous and forbidden: {}", self.swap.path);
|
||||
}
|
||||
if self.swap.priority < -1 || self.swap.priority > 32767 {
|
||||
anyhow::bail!("swap.priority must be between -1 and 32767");
|
||||
}
|
||||
}
|
||||
if self.anti_torrent.enabled && self.anti_torrent.max_connections_per_peer == 0 {
|
||||
anyhow::bail!("anti_torrent.max_connections_per_peer must be > 0");
|
||||
@@ -140,7 +150,15 @@ impl Config {
|
||||
required.push("systemctl");
|
||||
}
|
||||
if self.swap.enabled {
|
||||
required.extend(["fallocate", "chmod", "mkswap", "swapon", "sysctl"]);
|
||||
required.extend([
|
||||
"fallocate",
|
||||
"chmod",
|
||||
"mkswap",
|
||||
"swapon",
|
||||
"swapoff",
|
||||
"sysctl",
|
||||
"dd",
|
||||
]);
|
||||
}
|
||||
|
||||
for tool in required {
|
||||
@@ -209,7 +227,9 @@ fn tool_exists(tool: &str) -> bool {
|
||||
"chmod" => &[&["--help"]],
|
||||
"mkswap" => &[&["--help"]],
|
||||
"swapon" => &[&["--help"]],
|
||||
"swapoff" => &[&["--help"]],
|
||||
"sysctl" => &[&["--version"], &["--help"]],
|
||||
"dd" => &[&["--help"]],
|
||||
_ => &[&["--version"], &["--help"], &["-V"]],
|
||||
};
|
||||
|
||||
@@ -280,4 +300,44 @@ mod tests {
|
||||
assert_eq!(parse_tc_rate_bps("1000mbit").expect("bps"), 1_000_000_000);
|
||||
assert!(parse_tc_rate_bps("foo").is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn swap_rejects_dangerous_path() {
|
||||
let cfg = Config {
|
||||
amnezia: AmneziaConfig {
|
||||
container_names: vec!["x".into()],
|
||||
interface_candidates: vec!["awg0".into()],
|
||||
interface_patterns: vec!["awg*".into()],
|
||||
peer_ipv4_cidr: "10.8.1.0/24".into(),
|
||||
},
|
||||
traffic: TrafficConfig {
|
||||
enabled: true,
|
||||
peer_limit: "70mbit".into(),
|
||||
root_rate: "1000mbit".into(),
|
||||
reconcile_interval_secs: 15,
|
||||
container_ready_timeout_secs: 30,
|
||||
class_start_id: 10,
|
||||
ifb_name: "ifb0".into(),
|
||||
},
|
||||
anti_torrent: AntiTorrentConfig {
|
||||
enabled: false,
|
||||
max_connections_per_peer: 100,
|
||||
peer_ipv4_cidr: "10.8.1.0/24".into(),
|
||||
apply_in_amnezia_netns: false,
|
||||
},
|
||||
reboot: RebootConfig {
|
||||
enabled: false,
|
||||
window_start_utc: "01:00".into(),
|
||||
window_end_utc: "02:00".into(),
|
||||
},
|
||||
swap: SwapConfig {
|
||||
enabled: true,
|
||||
path: "/etc/fstab".into(),
|
||||
size_mb: 2048,
|
||||
priority: 1,
|
||||
swappiness: 1,
|
||||
},
|
||||
};
|
||||
assert!(cfg.validate_config().is_err());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user