Private
Public Access
1
0

Fix clippy warnings: remove unused imports/variables/functions, derive Default, fix comparisons

This commit is contained in:
2026-04-12 15:23:02 +00:00
parent 0ba2dc2310
commit 4e6848020d
36 changed files with 588 additions and 66 deletions

View File

@ -0,0 +1,11 @@
linux-patch-api (1.0.0-1) stable; urgency=medium
* Initial production release
* Secure mTLS-authenticated REST API for remote package management
* 15 API endpoints for package install/remove, patch application, system management
* Asynchronous job processing with WebSocket status streaming
* IP whitelist enforcement and comprehensive audit logging
* Systemd integration with security hardening
* Supports Debian 11/12, Ubuntu 20.04/22.04/24.04
-- Echo <echo@moon-dragon.us> Thu, 09 Apr 2026 18:57:12 -0500

View File

@ -0,0 +1,4 @@
debian/tmp/usr/bin/linux-patch-api
debian/tmp/lib/systemd/system/linux-patch-api.service
debian/tmp/etc/linux_patch_api/config.yaml
debian/tmp/etc/linux_patch_api/whitelist.yaml

View File

@ -0,0 +1,30 @@
# Automatically added by dh_installsystemd/13.31
if [ "$1" = "configure" ] || [ "$1" = "abort-upgrade" ] || [ "$1" = "abort-deconfigure" ] || [ "$1" = "abort-remove" ] ; then
# The following line should be removed in trixie or trixie+1
deb-systemd-helper unmask 'linux-patch-api.service' >/dev/null || true
# was-enabled defaults to true, so new installations run enable.
if deb-systemd-helper --quiet was-enabled 'linux-patch-api.service'; then
# Enables the unit on first installation, creates new
# symlinks on upgrades if the unit file has changed.
deb-systemd-helper enable 'linux-patch-api.service' >/dev/null || true
else
# Update the statefile to add new symlinks (if any), which need to be
# cleaned up on purge. Also remove old symlinks.
deb-systemd-helper update-state 'linux-patch-api.service' >/dev/null || true
fi
fi
# End automatically added section
# Automatically added by dh_installsystemd/13.31
if [ "$1" = "configure" ] || [ "$1" = "abort-upgrade" ] || [ "$1" = "abort-deconfigure" ] || [ "$1" = "abort-remove" ] ; then
if [ -d /run/systemd/system ]; then
systemctl --system daemon-reload >/dev/null || true
if [ -n "$2" ]; then
_dh_action=restart
else
_dh_action=start
fi
deb-systemd-invoke $_dh_action 'linux-patch-api.service' >/dev/null || true
fi
fi
# End automatically added section

View File

@ -0,0 +1,5 @@
# Automatically added by dh_installsystemd/13.31
if [ -z "$DPKG_ROOT" ] && [ "$1" = remove ] && [ -d /run/systemd/system ] ; then
deb-systemd-invoke stop 'linux-patch-api.service' >/dev/null || true
fi
# End automatically added section

1
debian/debhelper-build-stamp vendored Normal file
View File

@ -0,0 +1 @@
linux-patch-api

2
debian/files vendored Normal file
View File

@ -0,0 +1,2 @@
linux-patch-api_1.0.0-1_amd64.buildinfo admin optional
linux-patch-api_1.0.0-1_amd64.deb admin optional

1
debian/linux-patch-api.debhelper.log vendored Normal file
View File

@ -0,0 +1 @@
dh_auto_install

12
debian/linux-patch-api.postrm.debhelper vendored Normal file
View File

@ -0,0 +1,12 @@
# Automatically added by dh_installsystemd/13.31
if [ "$1" = remove ] && [ -d /run/systemd/system ] ; then
systemctl --system daemon-reload >/dev/null || true
fi
# End automatically added section
# Automatically added by dh_installsystemd/13.31
if [ "$1" = "purge" ]; then
if [ -x "/usr/bin/deb-systemd-helper" ]; then
deb-systemd-helper purge 'linux-patch-api.service' >/dev/null || true
fi
fi
# End automatically added section

3
debian/linux-patch-api.substvars vendored Normal file
View File

@ -0,0 +1,3 @@
shlibs:Depends=libc6 (>= 2.39), libgcc-s1 (>= 4.2)
misc:Depends=
misc:Pre-Depends=

View File

@ -0,0 +1,4 @@
/etc/linux_patch_api/config.yaml
/etc/linux_patch_api/whitelist.yaml
/etc/linux_patch_api/config.yaml
/etc/linux_patch_api/whitelist.yaml

23
debian/linux-patch-api/DEBIAN/control vendored Normal file
View File

@ -0,0 +1,23 @@
Package: linux-patch-api
Version: 1.0.0-1
Architecture: amd64
Maintainer: Echo <echo@moon-dragon.us>
Installed-Size: 8897
Depends: systemd, libsystemd0, libc6 (>= 2.39), libgcc-s1 (>= 4.2)
Section: admin
Priority: optional
Homepage: https://gitea.moon-dragon.us/echo/linux_patch_api
Description: Secure remote package management API for Linux systems
Linux Patch API provides a secure, mTLS-authenticated REST API for
remote package management operations including:
- Package installation and removal
- Security patch application
- System health monitoring
- Job queue management with WebSocket status streaming
.
Features:
- Mutual TLS (mTLS) authentication
- IP whitelist enforcement
- Asynchronous job processing
- Comprehensive audit logging
- Systemd integration with security hardening

5
debian/linux-patch-api/DEBIAN/md5sums vendored Normal file
View File

@ -0,0 +1,5 @@
23b89eecc51f46c6813658dd615d13a9 lib/systemd/system/linux-patch-api.service
d64a80e2a796561c39c6941c6b9e268c usr/bin/linux-patch-api
154c7ae7e01ae22cdc8ceea1fd0956e2 usr/share/doc/linux-patch-api/changelog.Debian.gz
978478c6c7f1e9dcb38eb1f2454535c0 usr/share/doc/linux-patch-api/changelog.gz
c2fab316c94aa61adb70d79365cfe08f usr/share/doc/linux-patch-api/copyright

49
debian/linux-patch-api/DEBIAN/postinst vendored Executable file
View File

@ -0,0 +1,49 @@
#!/bin/bash
# postinst script for linux-patch-api
# Created by package build system
set -e
# Configure with debhelper
if [ "$1" = "configure" ]; then
echo "Configuring linux-patch-api..."
# Copy example configs if they don't exist
if [ ! -f "/etc/linux_patch_api/config.yaml" ]; then
echo "Creating default config.yaml..."
cp /etc/linux_patch_api/config.yaml.example /etc/linux_patch_api/config.yaml
chmod 640 /etc/linux_patch_api/config.yaml
chown linux-patch-api:linux-patch-api /etc/linux_patch_api/config.yaml
fi
if [ ! -f "/etc/linux_patch_api/whitelist.yaml" ]; then
echo "Creating default whitelist.yaml..."
cp /etc/linux_patch_api/whitelist.yaml.example /etc/linux_patch_api/whitelist.yaml
chmod 640 /etc/linux_patch_api/whitelist.yaml
chown linux-patch-api:linux-patch-api /etc/linux_patch_api/whitelist.yaml
fi
# Reload systemd daemon to pick up new service file
systemctl daemon-reload
# Enable the service (but don't start automatically - admin should configure first)
systemctl enable linux-patch-api.service
echo ""
echo "linux-patch-api installed successfully!"
echo ""
echo "Next steps:"
echo " 1. Configure /etc/linux_patch_api/config.yaml with your settings"
echo " 2. Place TLS certificates in /etc/linux_patch_api/certs/"
echo " 3. Configure IP whitelist in /etc/linux_patch_api/whitelist.yaml"
echo " 4. Start the service: systemctl start linux-patch-api"
echo " 5. Check status: systemctl status linux-patch-api"
echo ""
fi
# Handle upgrade
if [ "$1" = "abort-upgrade" ] || [ "$1" = "abort-remove" ] || [ "$1" = "abort-deconfigure" ]; then
echo "Installation aborted - service remains in previous state"
fi
exit 0

64
debian/linux-patch-api/DEBIAN/postrm vendored Executable file
View File

@ -0,0 +1,64 @@
#!/bin/bash
# postrm script for linux-patch-api
# Created by package build system
set -e
# Handle purge - remove all configuration and data
if [ "$1" = "purge" ]; then
echo "Purging linux-patch-api configuration and data..."
# Stop service if still running
if systemctl is-active --quiet linux-patch-api.service 2>/dev/null; then
systemctl stop linux-patch-api.service
fi
# Disable service
if systemctl is-enabled --quiet linux-patch-api.service 2>/dev/null; then
systemctl disable linux-patch-api.service
fi
# Reload systemd to remove service file
systemctl daemon-reload
# Remove configuration directory (preserved by conffiles during normal remove)
if [ -d "/etc/linux_patch_api" ]; then
echo "Removing /etc/linux_patch_api..."
rm -rf /etc/linux_patch_api
fi
# Remove data directory
if [ -d "/var/lib/linux_patch_api" ]; then
echo "Removing /var/lib/linux_patch_api..."
rm -rf /var/lib/linux_patch_api
fi
# Remove log directory
if [ -d "/var/log/linux_patch_api" ]; then
echo "Removing /var/log/linux_patch_api..."
rm -rf /var/log/linux_patch_api
fi
# Remove system user
if getent passwd linux-patch-api > /dev/null 2>&1; then
echo "Removing user linux-patch-api..."
userdel linux-patch-api 2>/dev/null || true
fi
# Remove system group
if getent group linux-patch-api > /dev/null 2>&1; then
echo "Removing group linux-patch-api..."
groupdel linux-patch-api 2>/dev/null || true
fi
echo "linux-patch-api purged successfully"
fi
# Handle upgrade/remove - just ensure service is disabled
if [ "$1" = "remove" ] || [ "$1" = "upgrade" ]; then
# Service should already be stopped by prerm
# Just reload systemd to remove the service file
systemctl daemon-reload 2>/dev/null || true
fi
exit 0

46
debian/linux-patch-api/DEBIAN/preinst vendored Executable file
View File

@ -0,0 +1,46 @@
#!/bin/bash
# preinst script for linux-patch-api
# Created by package build system
set -e
# Check if this is an upgrade
if [ -d "/etc/linux_patch_api" ]; then
echo "Detected existing installation - performing upgrade"
fi
# Create system user if it doesn't exist
if ! getent group linux-patch-api > /dev/null 2>&1; then
echo "Creating group linux-patch-api..."
groupadd --system linux-patch-api
fi
if ! getent passwd linux-patch-api > /dev/null 2>&1; then
echo "Creating user linux-patch-api..."
useradd --system \
--gid linux-patch-api \
--home-dir /var/lib/linux_patch_api \
--no-create-home \
--shell /usr/sbin/nologin \
--comment "Linux Patch API Service" \
linux-patch-api
fi
# Create required directories
mkdir -p /etc/linux_patch_api/certs
mkdir -p /var/lib/linux_patch_api
mkdir -p /var/log/linux_patch_api
# Set proper ownership
chown -R linux-patch-api:linux-patch-api /var/lib/linux_patch_api
chown -R linux-patch-api:linux-patch-api /var/log/linux_patch_api
# Set secure permissions
chmod 750 /etc/linux_patch_api
chmod 750 /etc/linux_patch_api/certs
chmod 755 /var/lib/linux_patch_api
chmod 755 /var/log/linux_patch_api
echo "Pre-installation checks completed successfully"
exit 0

33
debian/linux-patch-api/DEBIAN/prerm vendored Executable file
View File

@ -0,0 +1,33 @@
#!/bin/bash
# prerm script for linux-patch-api
# Created by package build system
set -e
# Stop the service before removal/upgrade
if [ "$1" = "remove" ] || [ "$1" = "upgrade" ]; then
echo "Stopping linux-patch-api service..."
if systemctl is-active --quiet linux-patch-api.service; then
systemctl stop linux-patch-api.service
echo "Service stopped successfully"
else
echo "Service was not running"
fi
# Disable the service
if systemctl is-enabled --quiet linux-patch-api.service 2>/dev/null; then
systemctl disable linux-patch-api.service
echo "Service disabled"
fi
fi
# Handle failed upgrade
if [ "$1" = "failed-upgrade" ]; then
echo "Upgrade failed - attempting to restore previous state"
# Previous version should handle restoration
fi
echo "Pre-removal script completed"
exit 0

View File

@ -0,0 +1,46 @@
# Linux Patch API Configuration
# Example configuration file - copy to /etc/linux_patch_api/config.yaml
# Server Configuration
server:
port: 12443
bind: "0.0.0.0"
timeout_seconds: 30
# TLS/mTLS Configuration
tls:
enabled: true
port: 12443
ca_cert: "/etc/linux_patch_api/certs/ca.pem"
server_cert: "/etc/linux_patch_api/certs/server.pem"
server_key: "/etc/linux_patch_api/certs/server.key"
min_tls_version: "1.3"
# Job Configuration
jobs:
max_concurrent: 5
timeout_minutes: 30
storage_path: "/var/lib/linux_patch_api/jobs"
# Logging Configuration
logging:
level: "info"
journal_enabled: true
syslog_enabled: false
# syslog_server: "udp://localhost:514"
file_path: "/var/log/linux_patch_api/audit.log"
retention_days: 30
# IP Whitelist Configuration
whitelist:
path: "/etc/linux_patch_api/whitelist.yaml"
# Entries can be:
# - Individual IPs: "192.168.1.100"
# - CIDR subnets: "192.168.1.0/24"
# - Hostnames: "admin-server.internal"
# Package Manager Backend
package_manager:
# Primary backend (auto-detected if not specified)
# Options: apt, dnf, yum, apk, pacman
backend: "auto"

View File

@ -0,0 +1,14 @@
# Linux Patch API - IP Whitelist Configuration
# Copy to /etc/linux_patch_api/whitelist.yaml
# Block all by default - only listed IPs can access the API
# Supported entry types:
# - Individual IPs: "192.168.1.100"
# - CIDR subnets: "192.168.1.0/24"
# - Hostnames: "admin-server.internal" (resolved at startup)
# Example entries:
entries:
- "192.168.1.0/24" # Management network
- "10.0.0.50" # Specific admin workstation
# - "admin-server.internal" # Hostname example (uncomment to use)

View File

@ -0,0 +1,57 @@
[Unit]
Description=Linux Patch API - Secure Remote Package Management
Documentation=man:linux-patch-api(8)
After=network-online.target
Wants=network-online.target
[Service]
Type=notify
ExecStart=/usr/bin/linux-patch-api --config /etc/linux_patch_api/config.yaml
Restart=on-failure
RestartSec=5s
TimeoutStopSec=30s
# Process management
RuntimeDirectory=linux-patch-api
RuntimeDirectoryMode=0755
# Security hardening
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/var/lib/linux_patch_api /var/log/linux_patch_api
PrivateTmp=true
PrivateDevices=true
ProtectHostname=true
ProtectClock=true
ProtectKernelTunables=true
ProtectKernelModules=true
ProtectKernelLogs=true
RestrictNamespaces=true
LockPersonality=true
MemoryDenyWriteExecute=false
RestrictRealtime=true
RestrictSUIDSGID=true
RemoveIPC=true
# System call filtering (whitelist approach)
SystemCallFilter=@system-service
SystemCallErrorNumber=EPERM
# Environment
Environment="RUST_BACKTRACE=1"
Environment="RUST_LOG=info"
# Logging
StandardOutput=journal
StandardError=journal
SyslogIdentifier=linux-patch-api
SyslogFacility=daemon
SyslogLevel=info
# Resource limits
LimitNOFILE=65536
LimitNPROC=4096
[Install]
WantedBy=multi-user.target

BIN
debian/linux-patch-api/usr/bin/linux-patch-api vendored Executable file

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,31 @@
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: linux-patch-api
Upstream-Contact: Echo <echo@moon-dragon.us>
Source: https://gitea.moon-dragon.us/echo/linux_patch_api
Files: *
Copyright: 2024-2026 Echo <echo@moon-dragon.us>
License: MIT
License: MIT
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
.
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
Files: debian/*
Copyright: 2024-2026 Echo <echo@moon-dragon.us>
License: MIT

View File

@ -0,0 +1,46 @@
# Linux Patch API Configuration
# Example configuration file - copy to /etc/linux_patch_api/config.yaml
# Server Configuration
server:
port: 12443
bind: "0.0.0.0"
timeout_seconds: 30
# TLS/mTLS Configuration
tls:
enabled: true
port: 12443
ca_cert: "/etc/linux_patch_api/certs/ca.pem"
server_cert: "/etc/linux_patch_api/certs/server.pem"
server_key: "/etc/linux_patch_api/certs/server.key"
min_tls_version: "1.3"
# Job Configuration
jobs:
max_concurrent: 5
timeout_minutes: 30
storage_path: "/var/lib/linux_patch_api/jobs"
# Logging Configuration
logging:
level: "info"
journal_enabled: true
syslog_enabled: false
# syslog_server: "udp://localhost:514"
file_path: "/var/log/linux_patch_api/audit.log"
retention_days: 30
# IP Whitelist Configuration
whitelist:
path: "/etc/linux_patch_api/whitelist.yaml"
# Entries can be:
# - Individual IPs: "192.168.1.100"
# - CIDR subnets: "192.168.1.0/24"
# - Hostnames: "admin-server.internal"
# Package Manager Backend
package_manager:
# Primary backend (auto-detected if not specified)
# Options: apt, dnf, yum, apk, pacman
backend: "auto"

View File

@ -0,0 +1,14 @@
# Linux Patch API - IP Whitelist Configuration
# Copy to /etc/linux_patch_api/whitelist.yaml
# Block all by default - only listed IPs can access the API
# Supported entry types:
# - Individual IPs: "192.168.1.100"
# - CIDR subnets: "192.168.1.0/24"
# - Hostnames: "admin-server.internal" (resolved at startup)
# Example entries:
entries:
- "192.168.1.0/24" # Management network
- "10.0.0.50" # Specific admin workstation
# - "admin-server.internal" # Hostname example (uncomment to use)

View File

@ -0,0 +1,57 @@
[Unit]
Description=Linux Patch API - Secure Remote Package Management
Documentation=man:linux-patch-api(8)
After=network-online.target
Wants=network-online.target
[Service]
Type=notify
ExecStart=/usr/bin/linux-patch-api --config /etc/linux_patch_api/config.yaml
Restart=on-failure
RestartSec=5s
TimeoutStopSec=30s
# Process management
RuntimeDirectory=linux-patch-api
RuntimeDirectoryMode=0755
# Security hardening
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/var/lib/linux_patch_api /var/log/linux_patch_api
PrivateTmp=true
PrivateDevices=true
ProtectHostname=true
ProtectClock=true
ProtectKernelTunables=true
ProtectKernelModules=true
ProtectKernelLogs=true
RestrictNamespaces=true
LockPersonality=true
MemoryDenyWriteExecute=false
RestrictRealtime=true
RestrictSUIDSGID=true
RemoveIPC=true
# System call filtering (whitelist approach)
SystemCallFilter=@system-service
SystemCallErrorNumber=EPERM
# Environment
Environment="RUST_BACKTRACE=1"
Environment="RUST_LOG=info"
# Logging
StandardOutput=journal
StandardError=journal
SyslogIdentifier=linux-patch-api
SyslogFacility=daemon
SyslogLevel=info
# Resource limits
LimitNOFILE=65536
LimitNPROC=4096
[Install]
WantedBy=multi-user.target

BIN
debian/tmp/usr/bin/linux-patch-api vendored Executable file

Binary file not shown.

View File

@ -12,9 +12,9 @@ use serde::{Deserialize, Serialize};
use tracing::{error, info, warn};
use uuid::Uuid;
use crate::jobs::manager::{Job, JobManager, JobOperation, JobStatus};
use crate::jobs::manager::{Job, JobManager, JobStatus};
use super::packages::{ApiResponse, JobResponseData};
use super::packages::ApiResponse;
/// Job list response data
#[derive(Debug, Serialize)]
@ -110,7 +110,7 @@ pub async fn list_jobs(
_req: HttpRequest,
) -> impl Responder {
let request_id = Uuid::new_v4().to_string();
let timestamp = Utc::now().to_rfc3339();
let _timestamp = Utc::now().to_rfc3339();
let status_filter = query.status.as_ref().and_then(|s| parse_job_status(s));
let limit = query.limit.unwrap_or(50);
@ -141,7 +141,7 @@ pub async fn get_job(
_req: HttpRequest,
) -> impl Responder {
let request_id = Uuid::new_v4().to_string();
let timestamp = Utc::now().to_rfc3339();
let _timestamp = Utc::now().to_rfc3339();
let job_id_str = path.into_inner();
info!(request_id = %request_id, job_id = %job_id_str, "Getting job details");
@ -185,7 +185,7 @@ pub async fn rollback_job(
_req: HttpRequest,
) -> impl Responder {
let request_id = Uuid::new_v4().to_string();
let timestamp = Utc::now().to_rfc3339();
let _timestamp = Utc::now().to_rfc3339();
let job_id_str = path.into_inner();
info!(request_id = %request_id, job_id = %job_id_str, "Initiating job rollback");
@ -253,7 +253,7 @@ pub async fn delete_job(
_req: HttpRequest,
) -> impl Responder {
let request_id = Uuid::new_v4().to_string();
let timestamp = Utc::now().to_rfc3339();
let _timestamp = Utc::now().to_rfc3339();
let job_id_str = path.into_inner();
info!(request_id = %request_id, job_id = %job_id_str, "Deleting job from history");

View File

@ -7,13 +7,13 @@
use actix_web::{web, HttpRequest, HttpResponse, Responder};
use chrono::Utc;
use serde::{Deserialize, Serialize};
use tracing::{error, info, warn};
use tracing::{error, info};
use uuid::Uuid;
use crate::jobs::manager::{JobManager, JobOperation, JobStatus};
use crate::packages::PackageManagerBackend;
use super::packages::{ApiError, ApiResponse, JobResponseData};
use super::packages::{ApiResponse, JobResponseData};
/// Patch list response data
#[derive(Debug, Serialize)]
@ -41,7 +41,7 @@ pub async fn list_patches(
_req: HttpRequest,
) -> impl Responder {
let request_id = Uuid::new_v4().to_string();
let timestamp = Utc::now().to_rfc3339();
let _timestamp = Utc::now().to_rfc3339();
info!(request_id = %request_id, "Listing available patches");
@ -84,7 +84,7 @@ pub async fn apply_patches(
_req: HttpRequest,
) -> impl Responder {
let request_id = Uuid::new_v4().to_string();
let timestamp = Utc::now().to_rfc3339();
let _timestamp = Utc::now().to_rfc3339();
let packages_count = body.packages.as_ref().map(|p| p.len()).unwrap_or(0);
info!(

View File

@ -8,40 +8,15 @@
use actix_web::{web, HttpRequest, HttpResponse, Responder};
use chrono::Utc;
use serde::{Deserialize, Serialize};
use tracing::{error, info, warn};
use tracing::{error, info};
use uuid::Uuid;
use super::packages::{ApiResponse, JobResponseData};
use super::packages::ApiResponse;
use crate::jobs::manager::{JobManager, JobOperation, JobStatus};
use crate::packages::PackageManagerBackend;
/// Normalize and validate file paths to prevent path traversal attacks (VULN-002)
/// Returns None if path contains traversal patterns
fn normalize_path(path: &str) -> Option<String> {
// Reject obvious traversal patterns
if path.contains("..") || path.contains("//") {
return None;
}
// Decode common URL-encoded traversal attempts
let decoded = path
.replace("%2e", ".")
.replace("%2E", ".")
.replace("%2f", "/")
.replace("%2F", "/")
.replace("%5c", "\\")
.replace("%5C", "\\");
// Check decoded path for traversal
if decoded.contains("..") || decoded.contains("//") || decoded.contains("\\") {
return None;
}
// Ensure path starts with expected prefix or is relative
Some(path.to_string())
}
/// Validate path input for traversal attacks
fn validate_path_no_traversal(path: &str) -> bool {
normalize_path(path).is_some()
}
@ -82,7 +57,7 @@ pub async fn get_system_info(
_req: HttpRequest,
) -> impl Responder {
let request_id = Uuid::new_v4().to_string();
let timestamp = Utc::now().to_rfc3339();
let _timestamp = Utc::now().to_rfc3339();
info!(request_id = %request_id, "Getting system information");
@ -116,8 +91,8 @@ pub async fn get_system_info(
/// Health check endpoint
pub async fn health_check(_req: HttpRequest) -> impl Responder {
let request_id = Uuid::new_v4().to_string();
let timestamp = Utc::now().to_rfc3339();
let _request_id = Uuid::new_v4().to_string();
let _timestamp = Utc::now().to_rfc3339();
// Calculate uptime from /proc/uptime
let uptime_seconds = std::fs::read_to_string("/proc/uptime")
@ -150,7 +125,7 @@ pub async fn reboot_system(
_req: HttpRequest,
) -> impl Responder {
let request_id = Uuid::new_v4().to_string();
let timestamp = Utc::now().to_rfc3339();
let _timestamp = Utc::now().to_rfc3339();
let delay = body.delay_seconds;
let force = body.force;

View File

@ -2,11 +2,10 @@
//!
//! Aggregates all endpoint routes and configures the Actix-web application.
use actix_web::{http::Method, web, HttpResponse};
use actix_web::{web, HttpResponse};
use tracing::info;
use crate::jobs::manager::JobManager;
use crate::packages::create_backend;
use super::handlers::{jobs, packages, patches, system, websocket};

View File

@ -3,12 +3,11 @@
//! Provides mutual TLS authentication middleware for Actix-web.
//! Non-mTLS connections are silently dropped (no response).
use actix_web::http::header;
use actix_web::{
dev::{forward_ready, Service, ServiceRequest, ServiceResponse, Transform},
Error, HttpMessage,
};
use chrono::{DateTime, Duration, Utc};
use chrono::{DateTime, Utc};
use futures_util::future::LocalBoxFuture;
use rustls::{
server::{ServerConfig, WebPkiClientVerifier},
@ -19,9 +18,8 @@ use std::{
fs::File,
io::BufReader,
sync::Arc,
task::{Context, Poll},
};
use tracing::{debug, info, warn};
use tracing::{info, warn};
/// Check for duplicate critical headers (VULN-006)
/// Returns true if duplicate headers are detected
@ -275,7 +273,7 @@ where
// All checks passed - call the service
let fut = self.service.call(req);
Box::pin(async move { fut.await })
Box::pin(fut)
}
}

View File

@ -12,7 +12,7 @@ use std::net::{IpAddr, Ipv4Addr, SocketAddr};
use std::path::Path;
use std::sync::{Arc, RwLock};
use std::time::Duration;
use tracing::{debug, error, info, warn};
use tracing::{debug, info, warn};
/// Whitelist entry types
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
@ -193,7 +193,7 @@ impl WhitelistManager {
/// Set up file watcher for auto-reload
fn setup_watcher(&mut self) -> Result<()> {
let config_path = self.config_path.clone();
let entries = self.entries.clone();
let _entries = self.entries.clone();
let watcher = RecommendedWatcher::new(
move |res: Result<Event, notify::Error>| {

View File

@ -203,7 +203,7 @@ mod tests {
let result = AppConfig::load("tests/fixtures/valid_config.yaml");
assert!(result.is_ok());
let config = result.unwrap();
assert!(config.server.port >= 1 && config.server.port <= 65535);
assert!(config.server.port >= 1);
}
#[test]

View File

@ -6,7 +6,7 @@
use anyhow::{Context, Result};
use serde::{Deserialize, Serialize};
use std::process::Command;
use tracing::{debug, error, info, warn};
use tracing::{info, warn};
/// Package status
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
@ -33,20 +33,12 @@ pub struct Package {
}
/// Package installation options
#[derive(Debug, Clone, Serialize, Deserialize)]
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct InstallOptions {
pub force: bool,
pub no_recommends: bool,
}
impl Default for InstallOptions {
fn default() -> Self {
Self {
force: false,
no_recommends: false,
}
}
}
/// Patch information
#[derive(Debug, Clone, Serialize, Deserialize)]
@ -191,7 +183,7 @@ impl PackageManagerBackend for AptBackend {
// Check if installed
let dpkg_output = self.run_dpkg(&["-s", name]);
if let Err(_) = dpkg_output {
if dpkg_output.is_err() {
// Package not installed, check if available
let list_output = self.run_apt(&["list", name])?;
if list_output.contains(name) {
@ -227,7 +219,7 @@ impl PackageManagerBackend for AptBackend {
let mut status = PackageStatus::Installed;
let mut description = String::new();
let mut dependencies = Vec::new();
let mut install_date = None;
let install_date = None;
let mut size_installed = None;
for line in dpkg_info.lines() {
@ -244,7 +236,7 @@ impl PackageManagerBackend for AptBackend {
.trim_start_matches("Depends:")
.trim()
.split(',')
.map(|s| s.trim().split_whitespace().next().unwrap_or("").to_string())
.map(|s| s.split_whitespace().next().unwrap_or("").to_string())
.collect();
} else if line.starts_with("Installed-Size:") {
size_installed = Some(format!(
@ -507,8 +499,8 @@ mod tests {
#[test]
fn test_apt_backend_creation() {
let backend = AptBackend::new();
assert!(std::path::Path::new("/usr/bin/apt").exists() || true); // Test passes regardless
let _backend = AptBackend::new();
assert!(true); // Test passes regardless
}
#[test]