Private
Public Access
1
0

v0.2.0: Fix List Jobs bug, TLS 1.3 enforcement, client_disconnect_timeout, RwLock contention
Some checks failed
CI/CD Pipeline / Code Format (push) Failing after 1s
CI/CD Pipeline / Clippy Lints (push) Failing after 2s
CI/CD Pipeline / Unit Tests (push) Failing after 7s
CI/CD Pipeline / Build Debian Package (push) Has been skipped
CI/CD Pipeline / Build Debian Package (Ubuntu 22.04) (push) Has been skipped
CI/CD Pipeline / Build RPM Package (push) Has been skipped
CI/CD Pipeline / Build Alpine Package (push) Has been skipped
CI/CD Pipeline / Build Arch Package (push) Has been skipped
CI/CD Pipeline / Security Audit (push) Failing after 3s

Bug fixes:
- Fix List Jobs connection reset: Add client_disconnect_timeout (5s) to prevent TLS write truncation
- Enforce TLS 1.3 only: Add with_protocol_versions(&[&TLS13]) to rustls ServerConfig
- Fix RwLock contention: Release read lock before sorting in list_jobs()
- Fix systemd service: Remove ProtectSystem=strict (blocks package management)
- Fix systemd service: Change Type=notify to Type=simple (fixes restart hangs)
- Fix systemd service: Add DEBIAN_FRONTEND=noninteractive
- Fix systemd service: Add ReadWritePaths for apt/dpkg paths

CI/CD:
- Add Ubuntu 22.04 build job to CI workflow

E2E Testing:
- Add comprehensive E2E test suite (test_e2e.py)
- Tests cover health, packages, patches, jobs, security, and reboot endpoints

Other:
- Bump version to 0.2.0
- Add lessons learned documentation
This commit is contained in:
2026-05-02 20:59:02 +00:00
parent bda8d5c10c
commit 03786d1798
13 changed files with 903 additions and 7 deletions

View File

@ -12,6 +12,7 @@ use chrono::{DateTime, Duration, Utc};
use futures_util::future::LocalBoxFuture;
use rustls::{
server::{ServerConfig, WebPkiClientVerifier},
version::TLS13,
RootCertStore,
};
use rustls_pemfile::{certs, private_key};
@ -79,6 +80,8 @@ impl MtlsMiddleware {
let server_key = load_private_key(&self.config.server_key_path)?;
let config = ServerConfig::builder()
.with_protocol_versions(&[&TLS13])
.map_err(|e| MtlsError::ServerConfigError(format!("Failed to set TLS 1.3 only: {}", e)))?
.with_client_cert_verifier(client_verifier)
.with_single_cert(server_cert, server_key)
.map_err(|e| MtlsError::ServerConfigError(e.to_string()))?;

View File

@ -213,8 +213,11 @@ impl JobManager {
/// List all jobs with optional status filter
pub async fn list_jobs(&self, status_filter: Option<JobStatus>, limit: usize) -> Vec<Job> {
let jobs = self.jobs.read().await;
let mut result: Vec<Job> = jobs.values().cloned().collect();
// FIX: Clone under lock, then release before sorting to reduce lock contention
let mut result = {
let jobs = self.jobs.read().await;
jobs.values().cloned().collect::<Vec<Job>>()
}; // Lock released here
// Filter by status if provided
if let Some(status) = status_filter {

View File

@ -141,6 +141,8 @@ async fn main() -> Result<()> {
.workers(4)
// VULN-004: Configure header size limit to 8KB to prevent DoS via oversized headers
.client_request_timeout(std::time::Duration::from_secs(5))
// FIX: Set explicit client disconnect timeout to prevent connection resets on larger responses
.client_disconnect_timeout(std::time::Duration::from_secs(5))
.keep_alive(std::time::Duration::from_secs(15))
.max_connection_rate(1000);
info!(