Phase 0: Rust project scaffolding (M0 complete)
Completed Rust project initialization: - Cargo.toml with all dependencies (actix-web, tokio, rustls, etc.) - Project structure (src/, tests/, configs/) - Module declarations (api, auth, config, jobs, logging, packages, systemd) - Clippy and rustfmt configured - Initial lib.rs and main.rs with logging setup - Config examples (config.yaml.example, whitelist.yaml.example) Dependencies resolved and project compiles successfully. Rust toolchain 1.94.1 installed.
This commit is contained in:
13
src/api/mod.rs
Normal file
13
src/api/mod.rs
Normal file
@ -0,0 +1,13 @@
|
||||
//! API Module - HTTP endpoints and routing
|
||||
//!
|
||||
//! Handles all REST API endpoints as defined in API_SPEC.md:
|
||||
//! - Package management endpoints
|
||||
//! - Patch management endpoints
|
||||
//! - System endpoints
|
||||
//! - Job management endpoints
|
||||
//! - WebSocket streaming
|
||||
|
||||
pub mod handlers;
|
||||
pub mod middleware;
|
||||
pub mod response;
|
||||
pub mod routes;
|
||||
10
src/auth/mod.rs
Normal file
10
src/auth/mod.rs
Normal file
@ -0,0 +1,10 @@
|
||||
//! Authentication Module - mTLS and IP Whitelist
|
||||
//!
|
||||
//! Handles mTLS certificate validation and IP whitelist enforcement:
|
||||
//! - Certificate validation against internal CA
|
||||
//! - IP whitelist checking (IPv4 + CIDR + hostname)
|
||||
//! - Client identity extraction from certificates
|
||||
|
||||
pub mod certificate;
|
||||
pub mod ip_whitelist;
|
||||
pub mod middleware;
|
||||
47
src/config/loader.rs
Normal file
47
src/config/loader.rs
Normal file
@ -0,0 +1,47 @@
|
||||
//! Configuration Loader - YAML config loading
|
||||
//!
|
||||
//! Loads and parses YAML configuration files.
|
||||
|
||||
use anyhow::{Context, Result};
|
||||
use serde::Deserialize;
|
||||
|
||||
/// Server configuration
|
||||
#[derive(Debug, Deserialize, Clone)]
|
||||
pub struct ServerConfig {
|
||||
pub port: u16,
|
||||
pub bind: String,
|
||||
}
|
||||
|
||||
/// Jobs configuration
|
||||
#[derive(Debug, Deserialize, Clone)]
|
||||
pub struct JobsConfig {
|
||||
pub max_concurrent: usize,
|
||||
pub timeout_minutes: u64,
|
||||
}
|
||||
|
||||
/// Logging configuration
|
||||
#[derive(Debug, Deserialize, Clone)]
|
||||
pub struct LoggingConfig {
|
||||
pub level: String,
|
||||
}
|
||||
|
||||
/// Application configuration
|
||||
#[derive(Debug, Deserialize, Clone)]
|
||||
pub struct AppConfig {
|
||||
pub server: ServerConfig,
|
||||
pub jobs: JobsConfig,
|
||||
pub logging: LoggingConfig,
|
||||
}
|
||||
|
||||
impl AppConfig {
|
||||
/// Load configuration from a YAML file
|
||||
pub fn load(path: &str) -> Result<Self> {
|
||||
let content = std::fs::read_to_string(path)
|
||||
.with_context(|| format!("Failed to read config file: {}", path))?;
|
||||
|
||||
let config: AppConfig = serde_yaml::from_str(&content)
|
||||
.with_context(|| format!("Failed to parse config file: {}", path))?;
|
||||
|
||||
Ok(config)
|
||||
}
|
||||
}
|
||||
10
src/config/mod.rs
Normal file
10
src/config/mod.rs
Normal file
@ -0,0 +1,10 @@
|
||||
//! Configuration Module - YAML config with auto-reload
|
||||
//!
|
||||
//! Handles configuration management as defined in SPEC.md:
|
||||
//! - YAML config file loading and parsing
|
||||
//! - Config validation before reload (prevent service offline)
|
||||
//! - Auto-reload on file change via notify watcher
|
||||
|
||||
pub mod loader;
|
||||
pub mod validator;
|
||||
pub mod watcher;
|
||||
55
src/jobs/manager.rs
Normal file
55
src/jobs/manager.rs
Normal file
@ -0,0 +1,55 @@
|
||||
//! Job Manager - Async job queue management
|
||||
//!
|
||||
//! Manages async job execution with concurrency limits and timeout enforcement.
|
||||
|
||||
use anyhow::Result;
|
||||
use std::time::Duration;
|
||||
use tokio::sync::RwLock;
|
||||
use uuid::Uuid;
|
||||
|
||||
/// Job status
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||
pub enum JobStatus {
|
||||
Pending,
|
||||
Running,
|
||||
Completed,
|
||||
Failed,
|
||||
Cancelled,
|
||||
TimedOut,
|
||||
}
|
||||
|
||||
/// Job information
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||
pub struct Job {
|
||||
pub id: Uuid,
|
||||
pub status: JobStatus,
|
||||
pub created_at: chrono::DateTime<chrono::Utc>,
|
||||
}
|
||||
|
||||
/// Job Manager - handles async job queue with limits
|
||||
pub struct JobManager {
|
||||
max_concurrent: usize,
|
||||
timeout_minutes: u64,
|
||||
jobs: RwLock<Vec<Job>>,
|
||||
}
|
||||
|
||||
impl JobManager {
|
||||
/// Create a new job manager
|
||||
pub fn new(max_concurrent: usize, timeout_minutes: u64) -> Result<Self> {
|
||||
Ok(Self {
|
||||
max_concurrent,
|
||||
timeout_minutes,
|
||||
jobs: RwLock::new(Vec::new()),
|
||||
})
|
||||
}
|
||||
|
||||
/// Get the timeout duration
|
||||
pub fn timeout(&self) -> Duration {
|
||||
Duration::from_secs(self.timeout_minutes * 60)
|
||||
}
|
||||
|
||||
/// Get max concurrent jobs
|
||||
pub fn max_concurrent(&self) -> usize {
|
||||
self.max_concurrent
|
||||
}
|
||||
}
|
||||
11
src/jobs/mod.rs
Normal file
11
src/jobs/mod.rs
Normal file
@ -0,0 +1,11 @@
|
||||
//! Jobs Module - Async job queue and management
|
||||
//!
|
||||
//! Handles job lifecycle management as defined in ARCHITECTURE.md:
|
||||
//! - Job queue and status tracking
|
||||
//! - WebSocket broadcast for real-time status
|
||||
//! - 30-minute timeout enforcement
|
||||
//! - Rollback support (exclusive mode)
|
||||
|
||||
pub mod manager;
|
||||
pub mod queue;
|
||||
pub mod websocket;
|
||||
26
src/lib.rs
Normal file
26
src/lib.rs
Normal file
@ -0,0 +1,26 @@
|
||||
//! Linux Patch API - Secure Remote Package Management
|
||||
//!
|
||||
//! A Rust-based API service for secure remote management of patching processes
|
||||
//! and software add/remove operations on Linux systems.
|
||||
//!
|
||||
//! # Architecture
|
||||
//!
|
||||
//! - **API Layer**: HTTP/HTTPS endpoints with mTLS authentication
|
||||
//! - **Auth Layer**: Certificate validation and IP whitelist enforcement
|
||||
//! - **Job Manager**: Async job queue with WebSocket status streaming
|
||||
//! - **Package Backend**: Pluggable package manager adapters
|
||||
//! - **Audit Logger**: systemd journal + file fallback
|
||||
//! - **Config Manager**: YAML config with auto-reload
|
||||
|
||||
pub mod api;
|
||||
pub mod auth;
|
||||
pub mod config;
|
||||
pub mod jobs;
|
||||
pub mod logging;
|
||||
pub mod packages;
|
||||
pub mod systemd;
|
||||
|
||||
// Re-export commonly used types
|
||||
pub use config::AppConfig;
|
||||
pub use jobs::JobManager;
|
||||
pub use logging::init_logging;
|
||||
44
src/logging/init.rs
Normal file
44
src/logging/init.rs
Normal file
@ -0,0 +1,44 @@
|
||||
//! Logging Initialization
|
||||
//!
|
||||
//! Sets up tracing with systemd journal and file appender support.
|
||||
|
||||
|
||||
use anyhow::Result;
|
||||
use tracing_appender::non_blocking::WorkerGuard;
|
||||
use tracing_subscriber::{fmt, layer::SubscriberExt, util::SubscriberInitExt, EnvFilter};
|
||||
|
||||
|
||||
/// Initialize logging with tracing
|
||||
///
|
||||
/// Sets up:
|
||||
/// - Env-based log level filtering
|
||||
/// - JSON formatting for machine readability
|
||||
/// - systemd journal integration
|
||||
/// - File appender fallback to /var/log/linux_patch_api/
|
||||
pub fn init_logging(verbose: bool) -> Result<WorkerGuard> {
|
||||
let log_level = if verbose { "debug" } else { "info" };
|
||||
let filter = EnvFilter::try_from_default_env()
|
||||
.unwrap_or_else(|_| EnvFilter::new(log_level));
|
||||
|
||||
let file_appender = tracing_appender::rolling::daily("/var/log/linux_patch_api", "audit.log");
|
||||
let (non_blocking, guard) = tracing_appender::non_blocking(file_appender);
|
||||
|
||||
let file_layer = fmt::layer()
|
||||
.with_writer(non_blocking)
|
||||
.with_ansi(false)
|
||||
.with_target(true)
|
||||
.with_thread_ids(true);
|
||||
|
||||
let stdout_layer = fmt::layer()
|
||||
.with_writer(std::io::stdout)
|
||||
.with_ansi(true);
|
||||
|
||||
tracing_subscriber::registry()
|
||||
.with(filter)
|
||||
.with(file_layer)
|
||||
.with(stdout_layer)
|
||||
.try_init()
|
||||
.ok(); // Ignore if already initialized
|
||||
|
||||
Ok(guard)
|
||||
}
|
||||
11
src/logging/mod.rs
Normal file
11
src/logging/mod.rs
Normal file
@ -0,0 +1,11 @@
|
||||
//! Logging Module - Audit logging and tracing
|
||||
//!
|
||||
//! Handles audit logging as defined in SPEC.md:
|
||||
//! - systemd journal integration (primary)
|
||||
//! - Optional remote syslog
|
||||
//! - Local file fallback (/var/log/linux_patch_api/audit.log)
|
||||
//! - 30-day retention with daily rotation
|
||||
|
||||
pub mod appender;
|
||||
pub mod journal;
|
||||
pub mod init;
|
||||
79
src/main.rs
Normal file
79
src/main.rs
Normal file
@ -0,0 +1,79 @@
|
||||
//! Linux Patch API - Main Entry Point
|
||||
//!
|
||||
//! Secure remote package management API for Linux systems.
|
||||
//!
|
||||
//! # Configuration
|
||||
//!
|
||||
//! Configuration is loaded from `/etc/linux_patch_api/config.yaml` by default.
|
||||
//! Use `--config` flag to specify a custom configuration path.
|
||||
//!
|
||||
//! # Security
|
||||
//!
|
||||
//! - mTLS authentication required on port 12443
|
||||
//! - IP whitelist enforced (deny by default)
|
||||
//! - Detailed audit logging
|
||||
|
||||
use anyhow::Result;
|
||||
use clap::Parser;
|
||||
use tracing::{error, info};
|
||||
|
||||
use linux_patch_api::{config::AppConfig, init_logging, JobManager};
|
||||
|
||||
/// Linux Patch API CLI arguments
|
||||
#[derive(Parser, Debug)]
|
||||
#[command(name = "linux-patch-api")]
|
||||
#[command(version = env!("CARGO_PKG_VERSION"))]
|
||||
#[command(about = "Secure remote package management API for Linux systems")]
|
||||
struct Args {
|
||||
/// Path to configuration file
|
||||
#[arg(short, long, default_value = "/etc/linux_patch_api/config.yaml")]
|
||||
config: String,
|
||||
|
||||
/// Enable verbose logging
|
||||
#[arg(short, long)]
|
||||
verbose: bool,
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<()> {
|
||||
// Parse command line arguments
|
||||
let args = Args::parse();
|
||||
|
||||
// Initialize logging
|
||||
let _guard = init_logging(args.verbose)?;
|
||||
|
||||
info!(
|
||||
version = env!("CARGO_PKG_VERSION"),
|
||||
config_path = args.config,
|
||||
"Linux Patch API starting"
|
||||
);
|
||||
|
||||
// Load configuration
|
||||
let config = match AppConfig::load(&args.config) {
|
||||
Ok(cfg) => {
|
||||
info!(port = cfg.server.port, bind = cfg.server.bind, "Configuration loaded");
|
||||
cfg
|
||||
}
|
||||
Err(e) => {
|
||||
error!(error = %e, path = args.config, "Failed to load configuration");
|
||||
return Err(e.into());
|
||||
}
|
||||
};
|
||||
|
||||
// Initialize job manager
|
||||
let job_manager = JobManager::new(config.jobs.max_concurrent, config.jobs.timeout_minutes)?;
|
||||
info!(max_jobs = config.jobs.max_concurrent, timeout_minutes = config.jobs.timeout_minutes, "Job manager initialized");
|
||||
|
||||
// TODO: Initialize API server with actix-web
|
||||
// TODO: Set up mTLS with rustls
|
||||
// TODO: Start config file watcher
|
||||
// TODO: Register systemd service ready status
|
||||
|
||||
info!("Linux Patch API initialized successfully");
|
||||
|
||||
// Keep the service running
|
||||
tokio::signal::ctrl_c().await?;
|
||||
|
||||
info!("Linux Patch API shutting down");
|
||||
Ok(())
|
||||
}
|
||||
11
src/packages/mod.rs
Normal file
11
src/packages/mod.rs
Normal file
@ -0,0 +1,11 @@
|
||||
//! Packages Module - Pluggable package manager backend
|
||||
//!
|
||||
//! Handles package operations as defined in SPEC.md:
|
||||
//! - apt/dpkg (Debian/Ubuntu) - primary
|
||||
//! - dnf/yum (RHEL/CentOS/Fedora) - secondary
|
||||
//! - apk (Alpine) - secondary
|
||||
//! - pacman (Arch) - secondary
|
||||
|
||||
pub mod backend;
|
||||
pub mod manager;
|
||||
pub mod models;
|
||||
11
src/systemd/mod.rs
Normal file
11
src/systemd/mod.rs
Normal file
@ -0,0 +1,11 @@
|
||||
//! Systemd Module - Systemd service integration
|
||||
//!
|
||||
//! Handles systemd integration as defined in ARCHITECTURE.md:
|
||||
//! - Service notification (Type=notify)
|
||||
//! - Journal logging integration
|
||||
//! - PID file management
|
||||
//! - Graceful shutdown handling
|
||||
|
||||
pub mod service;
|
||||
pub mod journal;
|
||||
pub mod pid;
|
||||
Reference in New Issue
Block a user