Private
Public Access
1
0

Compare commits

...

2 Commits

Author SHA1 Message Date
9e42f32270 fix: remove sudo from apt commands and RestrictSUIDSGID from service
All checks were successful
CI/CD Pipeline / Code Format (push) Successful in 2s
CI/CD Pipeline / Clippy Lints (push) Successful in 1m17s
CI/CD Pipeline / Unit Tests (push) Successful in 56s
CI/CD Pipeline / Security Audit (push) Successful in 15s
CI/CD Pipeline / Build Debian Package (Ubuntu 22.04) (push) Successful in 1m57s
CI/CD Pipeline / Build Arch Package (push) Successful in 1m53s
CI/CD Pipeline / Build Alpine Package (push) Successful in 3m17s
CI/CD Pipeline / Build RPM Package (push) Successful in 3m36s
CI/CD Pipeline / Build Debian Package (push) Successful in 2m11s
- Remove sudo from apt command execution (service runs as root)
- Remove RestrictSUIDSGID from systemd service (blocks setuid for apt/dpkg)
- Remove NoNewPrivileges from systemd service (blocks sudo PERM_SUDOERS)
- Bump version to 0.3.2
2026-05-03 02:24:52 +00:00
2b35a143da fix: implement actual system reboot via shutdown/systemctl commands
All checks were successful
CI/CD Pipeline / Code Format (push) Successful in 2s
CI/CD Pipeline / Clippy Lints (push) Successful in 40s
CI/CD Pipeline / Unit Tests (push) Successful in 1m27s
CI/CD Pipeline / Security Audit (push) Successful in 4s
CI/CD Pipeline / Build Arch Package (push) Successful in 1m56s
CI/CD Pipeline / Build Debian Package (Ubuntu 22.04) (push) Successful in 2m32s
CI/CD Pipeline / Build Alpine Package (push) Successful in 3m25s
CI/CD Pipeline / Build RPM Package (push) Successful in 3m44s
CI/CD Pipeline / Build Debian Package (push) Successful in 3m0s
- Fix reboot_system() to use shutdown -r +N for delayed reboots
- Fix patches handler to call reboot_system() instead of just logging
- Add CAP_SYS_BOOT capability to systemd service for LXC reboot support
- Remove unused warn import from packages/mod.rs
- Bump version to 0.3.1
2026-05-03 01:37:22 +00:00
8 changed files with 81 additions and 27 deletions

Binary file not shown.

2
Cargo.lock generated
View File

@ -1859,7 +1859,7 @@ dependencies = [
[[package]] [[package]]
name = "linux-patch-api" name = "linux-patch-api"
version = "0.3.0" version = "0.3.2"
dependencies = [ dependencies = [
"actix", "actix",
"actix-rt", "actix-rt",

View File

@ -1,6 +1,6 @@
[package] [package]
name = "linux-patch-api" name = "linux-patch-api"
version = "0.3.0" version = "0.3.2"
edition = "2021" edition = "2021"
authors = ["Echo <echo@moon-dragon.us>"] authors = ["Echo <echo@moon-dragon.us>"]
description = "Secure remote package management API for Linux systems" description = "Secure remote package management API for Linux systems"

View File

@ -17,7 +17,9 @@ RuntimeDirectory=linux-patch-api
RuntimeDirectoryMode=0755 RuntimeDirectoryMode=0755
# Security hardening # 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 # ProtectSystem removed - package management requires write access to /usr, /etc, /lib
# Network security provided by mTLS + IP whitelist # Network security provided by mTLS + IP whitelist
ProtectHome=true ProtectHome=true
@ -34,7 +36,7 @@ RestrictNamespaces=true
LockPersonality=true LockPersonality=true
MemoryDenyWriteExecute=false MemoryDenyWriteExecute=false
RestrictRealtime=true RestrictRealtime=true
RestrictSUIDSGID=true # RestrictSUIDSGID removed - package management requires setuid/setgid for apt/dpkg
RemoveIPC=true RemoveIPC=true
# System call filtering (whitelist approach) # System call filtering (whitelist approach)

18
debian/changelog vendored
View File

@ -1,3 +1,21 @@
linux-patch-api (0.3.2-1) unstable; urgency=low
* Fix package install: Remove sudo from apt commands (service runs as root)
* Fix reboot endpoint: Implement actual system reboot via shutdown/systemctl
* Fix patches handler: Call reboot_system() instead of just logging
* Remove NoNewPrivileges and RestrictSUIDSGID from systemd service
* Add CAP_SYS_BOOT capability to systemd service for LXC reboot support
* Fix dpkg packaging: Remove linux-patch-api user creation, fix directory ownership
-- Echo <echo@moon-dragon.us> Sat, 02 May 2026 21:25:00 -0500
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 <echo@moon-dragon.us> Sat, 02 May 2026 20:37:00 -0500
linux-patch-api (0.3.0-1) unstable; urgency=low linux-patch-api (0.3.0-1) unstable; urgency=low
* v0.3.0 beta release * v0.3.0 beta release

View File

@ -139,7 +139,22 @@ pub async fn apply_patches(
), ),
) )
.await; .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) => { Err(e) => {

View File

@ -6,7 +6,7 @@
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::process::Command; use std::process::Command;
use tracing::{info, warn}; use tracing::info;
/// Package status /// Package status
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
@ -98,18 +98,9 @@ impl AptBackend {
/// Run apt command and capture output /// Run apt command and capture output
fn run_apt(&self, args: &[&str]) -> Result<String> { fn run_apt(&self, args: &[&str]) -> Result<String> {
// Use sudo for operations that modify packages (install, upgrade, remove, purge) // Service runs as root - no sudo needed for apt commands
let needs_sudo = args.first().is_some_and(|&cmd| { let program = "apt";
matches!( let cmd_args: Vec<&str> = args.to_vec();
cmd,
"install" | "upgrade" | "remove" | "purge" | "dist-upgrade" | "autoremove"
)
});
let (program, cmd_args): (&str, Vec<&str>) = if needs_sudo {
("sudo", ["apt"].iter().chain(args.iter()).copied().collect())
} else {
("apt", args.to_vec())
};
let output = Command::new(program) let output = Command::new(program)
.args(&cmd_args) .args(&cmd_args)
@ -466,17 +457,27 @@ impl PackageManagerBackend for AptBackend {
fn reboot_system(&self, delay_seconds: u64) -> Result<()> { fn reboot_system(&self, delay_seconds: u64) -> Result<()> {
if delay_seconds > 0 { if delay_seconds > 0 {
info!("Scheduling reboot in {} seconds", delay_seconds); // Use shutdown command for delayed reboot (converts seconds to minutes, minimum 1)
// In production, would use systemd shutdown scheduler let delay_minutes = std::cmp::max(1u64, delay_seconds.div_ceil(60));
warn!("Delayed reboot not fully implemented - would use systemd in production"); 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(()) Ok(())
} }
} }

View File

@ -29,3 +29,21 @@
**Correction:** Always verify binary versions match before testing. Different BuildIDs mean different code. **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. **Rule:** Check binary versions (file size, BuildID, --version output) on all target systems before testing.
**Status:** Active **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