WP-10: contract and failing tests for OS and package inventory
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
55
backend/crates/domain/src/host.rs
Normal file
55
backend/crates/domain/src/host.rs
Normal file
@ -0,0 +1,55 @@
|
||||
//! Host inventory: operating system and installed packages.
|
||||
use chrono::{DateTime, Utc};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct OsInfo {
|
||||
pub hostname: String,
|
||||
pub name: String,
|
||||
pub version: String,
|
||||
pub kernel: String,
|
||||
pub uptime_secs: u64,
|
||||
pub reboot_required: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub enum PackageSource {
|
||||
Apt,
|
||||
Snap,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct Package {
|
||||
pub name: String,
|
||||
pub source: PackageSource,
|
||||
pub installed: String,
|
||||
/// Newer version available, if any.
|
||||
pub candidate: Option<String>,
|
||||
pub is_security: bool,
|
||||
}
|
||||
|
||||
impl Package {
|
||||
pub fn is_upgradable(&self) -> bool {
|
||||
self.candidate.is_some()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct Inventory {
|
||||
pub os: OsInfo,
|
||||
pub packages: Vec<Package>,
|
||||
pub refreshed_at: DateTime<Utc>,
|
||||
}
|
||||
|
||||
impl Inventory {
|
||||
pub fn upgradable(&self) -> usize {
|
||||
self.packages.iter().filter(|p| p.is_upgradable()).count()
|
||||
}
|
||||
pub fn security_upgrades(&self) -> usize {
|
||||
self.packages
|
||||
.iter()
|
||||
.filter(|p| p.is_upgradable() && p.is_security)
|
||||
.count()
|
||||
}
|
||||
}
|
||||
@ -2,6 +2,7 @@
|
||||
//! layer depends on. No I/O here.
|
||||
pub mod auth;
|
||||
pub mod error;
|
||||
pub mod host;
|
||||
pub mod jobs;
|
||||
pub mod ports;
|
||||
pub mod settings;
|
||||
|
||||
@ -3,6 +3,7 @@ use async_trait::async_trait;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::auth::{AccessClaims, AuthEvent, RefreshToken};
|
||||
use crate::host::{Inventory, OsInfo, Package};
|
||||
use crate::jobs::{JobKind, JobRun, JobStatus};
|
||||
use crate::settings::SmtpSettings;
|
||||
use crate::user::{User, UserUpdate};
|
||||
@ -76,3 +77,16 @@ pub trait JobRunRepository: Send + Sync {
|
||||
async fn find_running(&self, kind: JobKind) -> Result<Option<JobRun>, DomainError>;
|
||||
async fn last_finished(&self, kind: JobKind) -> Result<Option<JobRun>, DomainError>;
|
||||
}
|
||||
|
||||
/// Reads the state of the Debian host.
|
||||
#[async_trait]
|
||||
pub trait HostInspector: Send + Sync {
|
||||
async fn os_info(&self) -> Result<OsInfo, DomainError>;
|
||||
async fn packages(&self) -> Result<Vec<Package>, DomainError>;
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
pub trait InventoryRepository: Send + Sync {
|
||||
async fn save(&self, inventory: &Inventory) -> Result<(), DomainError>;
|
||||
async fn load(&self) -> Result<Option<Inventory>, DomainError>;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user