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:
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
/target
|
||||||
3753
Cargo.lock
generated
Normal file
3753
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
91
Cargo.toml
Normal file
91
Cargo.toml
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
[package]
|
||||||
|
name = "linux-patch-api"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
authors = ["Echo <echo@moon-dragon.us>"]
|
||||||
|
description = "Secure remote package management API for Linux systems"
|
||||||
|
license = "MIT"
|
||||||
|
repository = "https://gitea.moon-dragon.us/echo/linux_patch_api"
|
||||||
|
rust-version = "1.75"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
# Web framework (Actix-web for HTTP API)
|
||||||
|
actix-web = "4"
|
||||||
|
actix-rt = "2"
|
||||||
|
|
||||||
|
# Async runtime
|
||||||
|
tokio = { version = "1", features = ["full"] }
|
||||||
|
|
||||||
|
# TLS/mTLS (rustls for modern TLS 1.3)
|
||||||
|
rustls = "0.23"
|
||||||
|
rustls-pemfile = "2"
|
||||||
|
x509-parser = "0.16"
|
||||||
|
|
||||||
|
# WebSocket support
|
||||||
|
tokio-tungstenite = "0.21"
|
||||||
|
futures-util = "0.3"
|
||||||
|
|
||||||
|
# Serialization
|
||||||
|
serde = { version = "1", features = ["derive"] }
|
||||||
|
serde_json = "1"
|
||||||
|
serde_yaml = "0.9"
|
||||||
|
|
||||||
|
# Configuration
|
||||||
|
config = "0.14"
|
||||||
|
notify = "6"
|
||||||
|
|
||||||
|
|
||||||
|
# Logging
|
||||||
|
tracing = "0.1"
|
||||||
|
tracing-subscriber = { version = "0.3", features = ["env-filter", "json"] }
|
||||||
|
tracing-appender = "0.2"
|
||||||
|
|
||||||
|
|
||||||
|
# UUID for request IDs and job IDs
|
||||||
|
uuid = { version = "1", features = ["v4", "serde"] }
|
||||||
|
|
||||||
|
# Time/Date
|
||||||
|
chrono = { version = "0.4", features = ["serde"] }
|
||||||
|
|
||||||
|
# Error handling
|
||||||
|
thiserror = "1"
|
||||||
|
anyhow = "1"
|
||||||
|
|
||||||
|
# Async channels
|
||||||
|
async-channel = "2"
|
||||||
|
|
||||||
|
# Process management (for package operations)
|
||||||
|
sysinfo = "0.30"
|
||||||
|
|
||||||
|
# Network utilities
|
||||||
|
addr = "0.15"
|
||||||
|
|
||||||
|
# Clap for CLI arguments
|
||||||
|
clap = { version = "4", features = ["derive", "env"] }
|
||||||
|
|
||||||
|
|
||||||
|
# Systemd integration
|
||||||
|
systemd = "0.10"
|
||||||
|
|
||||||
|
pidlock = "0.2"
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
actix-rt = "2"
|
||||||
|
tokio-test = "0.4"
|
||||||
|
wiremock = "0.6"
|
||||||
|
serial_test = "3"
|
||||||
|
|
||||||
|
[profile.release]
|
||||||
|
lto = true
|
||||||
|
codegen-units = 1
|
||||||
|
panic = "abort"
|
||||||
|
strip = true
|
||||||
|
opt-level = 3
|
||||||
|
|
||||||
|
[profile.dev]
|
||||||
|
opt-level = 0
|
||||||
|
debug = true
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "linux-patch-api"
|
||||||
|
path = "src/main.rs"
|
||||||
@ -112,7 +112,7 @@
|
|||||||
|
|
||||||
| Milestone | Description | Target Date | Status |
|
| Milestone | Description | Target Date | Status |
|
||||||
|-----------|-------------|-------------|--------|
|
|-----------|-------------|-------------|--------|
|
||||||
| M0 | Phase 0 complete (scaffolding) | 2026-04-12 | ⏳ Pending |
|
| M0 | Phase 0 complete (scaffolding) | 2026-04-09 | ✅ Complete |
|
||||||
| M1 | All spec documents complete | 2026-04-09 | ✅ Complete |
|
| M1 | All spec documents complete | 2026-04-09 | ✅ Complete |
|
||||||
| M2 | Development environment ready | 2026-04-15 | ⏳ Pending |
|
| M2 | Development environment ready | 2026-04-15 | ⏳ Pending |
|
||||||
| M3 | CI/CD pipeline operational | 2026-04-22 | ⏳ Pending |
|
| M3 | CI/CD pipeline operational | 2026-04-22 | ⏳ Pending |
|
||||||
|
|||||||
46
configs/config.yaml.example
Normal file
46
configs/config.yaml.example
Normal 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"
|
||||||
14
configs/whitelist.yaml.example
Normal file
14
configs/whitelist.yaml.example
Normal 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)
|
||||||
0
rustfmt.toml
Normal file
0
rustfmt.toml
Normal file
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