diff --git a/.a0proj/audit.db b/.a0proj/audit.db index 0baf9ea..510ab39 100644 Binary files a/.a0proj/audit.db and b/.a0proj/audit.db differ diff --git a/Cargo.lock b/Cargo.lock index b553d9a..0674151 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1859,7 +1859,7 @@ dependencies = [ [[package]] name = "linux-patch-api" -version = "0.3.0" +version = "0.3.1" dependencies = [ "actix", "actix-rt", diff --git a/Cargo.toml b/Cargo.toml index d81f9d3..3a84b74 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "linux-patch-api" -version = "0.3.0" +version = "0.3.1" edition = "2021" authors = ["Echo "] description = "Secure remote package management API for Linux systems" diff --git a/configs/linux-patch-api.service b/configs/linux-patch-api.service index 41791c7..171ee54 100644 --- a/configs/linux-patch-api.service +++ b/configs/linux-patch-api.service @@ -18,6 +18,9 @@ RuntimeDirectoryMode=0755 # Security hardening NoNewPrivileges=true +# Allow reboot capability for scheduled reboots +CapabilityBoundingSet=CAP_SYS_BOOT +AmbientCapabilities=CAP_SYS_BOOT # ProtectSystem removed - package management requires write access to /usr, /etc, /lib # Network security provided by mTLS + IP whitelist ProtectHome=true diff --git a/debian/changelog b/debian/changelog index d887fb6..37a5aa0 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,11 @@ +linux-patch-api (0.3.1-1) unstable; urgency=low + + * Fix reboot endpoint: Implement actual system reboot via shutdown/systemctl + * Fix patches handler: Call reboot_system() instead of just logging + * Add CAP_SYS_BOOT capability to systemd service for LXC reboot support + * Remove unused warn import + + -- Echo Sat, 02 May 2026 20:37:00 -0500 linux-patch-api (0.3.0-1) unstable; urgency=low * v0.3.0 beta release diff --git a/src/api/handlers/patches.rs b/src/api/handlers/patches.rs index 98e7e93..a00c0b2 100644 --- a/src/api/handlers/patches.rs +++ b/src/api/handlers/patches.rs @@ -139,7 +139,22 @@ pub async fn apply_patches( ), ) .await; - // In production, would trigger actual reboot via system handler + // Trigger actual reboot via system handler + match backend_clone.reboot_system(request.reboot_delay_seconds) { + Ok(_) => { + let _ = job_manager_clone + .add_job_log( + &job_id_clone, + "Reboot command executed".to_string(), + ) + .await; + } + Err(e) => { + let _ = job_manager_clone + .add_job_log(&job_id_clone, format!("Reboot failed: {}", e)) + .await; + } + } } } Err(e) => { diff --git a/src/packages/mod.rs b/src/packages/mod.rs index 2d89c08..b3a712d 100644 --- a/src/packages/mod.rs +++ b/src/packages/mod.rs @@ -6,7 +6,7 @@ use anyhow::{Context, Result}; use serde::{Deserialize, Serialize}; use std::process::Command; -use tracing::{info, warn}; +use tracing::info; /// Package status #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] @@ -466,17 +466,27 @@ impl PackageManagerBackend for AptBackend { fn reboot_system(&self, delay_seconds: u64) -> Result<()> { if delay_seconds > 0 { - info!("Scheduling reboot in {} seconds", delay_seconds); - // In production, would use systemd shutdown scheduler - warn!("Delayed reboot not fully implemented - would use systemd in production"); + // Use shutdown command for delayed reboot (converts seconds to minutes, minimum 1) + let delay_minutes = std::cmp::max(1u64, delay_seconds.div_ceil(60)); + info!( + "Scheduling system reboot in {} minutes (requested {} seconds)", + delay_minutes, delay_seconds + ); + Command::new("shutdown") + .args(["-r", &format!("+{}", delay_minutes)]) + .status() + .context("Failed to schedule delayed reboot")?; + info!("System reboot scheduled in {} minutes", delay_minutes); + } else { + // Immediate reboot using systemctl + info!("Initiating immediate system reboot"); + Command::new("systemctl") + .arg("reboot") + .status() + .context("Failed to execute reboot command")?; + info!("System reboot initiated"); } - Command::new("systemctl") - .arg("reboot") - .status() - .context("Failed to execute reboot command")?; - - info!("System reboot initiated"); Ok(()) } } diff --git a/tasks/lessons.md b/tasks/lessons.md index d80c121..32ecd86 100644 --- a/tasks/lessons.md +++ b/tasks/lessons.md @@ -29,3 +29,21 @@ **Correction:** Always verify binary versions match before testing. Different BuildIDs mean different code. **Rule:** Check binary versions (file size, BuildID, --version output) on all target systems before testing. **Status:** Active + +## 2026-05-02 - Always run cargo fmt AND cargo clippy locally before pushing +**Mistake:** Pushed code changes without running cargo fmt and cargo clippy locally, causing 8 CI iterations to fix formatting and lint errors. +**Correction:** Run `cargo fmt --all -- --check` and `cargo clippy --all-targets --all-features -- -D warnings` locally before every push. +**Rule:** ALWAYS run cargo fmt AND cargo clippy locally before pushing to Gitea. Fix all errors before pushing. +**Status:** Active + +## 2026-05-02 - rustls 0.23 API: builder() vs builder_with_provider() +**Mistake:** Used ServerConfig::builder() which returns WantsVerifier state, then called with_protocol_versions() which requires WantsVersions state. +**Correction:** Use ServerConfig::builder_with_provider(Arc::new(aws_lc_rs::default_provider())) to get WantsVersions state. Also need aws_lc_rs feature in Cargo.toml. +**Rule:** In rustls 0.23, to set protocol versions, use builder_with_provider() not builder(). The builder() shortcut skips version negotiation. +**Status:** Active + +## 2026-05-02 - apt broken deps block unrelated package installs +**Mistake:** CI failed because openssh-server on runner had version mismatch (13.16 server vs 13.15 client), blocking all apt-get install operations. +**Correction:** Add `sudo apt-get -f install -y` before `sudo apt-get install` in CI workflow to fix broken deps automatically. +**Rule:** Always add `apt-get -f install -y` before `apt-get install` in CI workflows. Runners may have broken apt state from partial upgrades. +**Status:** Active