Private
Public Access
1
0

feat: add CRL health status schema and UI (PR 3 of 6)
All checks were successful
CI Pipeline / Rust Format Check (push) Successful in 5s
CI Pipeline / Clippy Lints (push) Successful in 52s
CI Pipeline / Rust Unit Tests (push) Successful in 1m8s
CI Pipeline / Security Audit (push) Successful in 5s
CI Pipeline / Frontend Lint & Type Check (push) Successful in 15s
CI Pipeline / Build .deb & Release (push) Has been skipped

* feat: add CRL health status schema and UI (PR 3 of 6)

* fix(lint): strict equality for crl_age_seconds

---------

Co-authored-by: Draco Lunaris <331325+Draco-Lunaris@users.noreply.github.com>
This commit is contained in:
Draco-Lunaris-Echo
2026-06-05 16:17:17 -05:00
committed by GitHub
parent 5aec9e629c
commit ea8337b944
12 changed files with 345 additions and 78 deletions

5
crates/pm-web/src/routes/hosts.rs Executable file → Normal file
View File

@ -133,6 +133,7 @@ async fn list_hosts(
ELSE 'all_healthy'
END AS health_check_status,
h.registered_at
h.crl_status
FROM hosts h
LEFT JOIN host_patch_data hpd ON hpd.host_id = h.id
ORDER BY h.fqdn
@ -166,6 +167,7 @@ async fn list_hosts(
ELSE 'all_healthy'
END AS health_check_status,
h.registered_at
h.crl_status
FROM hosts h
LEFT JOIN host_patch_data hpd ON hpd.host_id = h.id
WHERE
@ -319,7 +321,8 @@ async fn get_host(
SELECT id, fqdn, host(ip_address)::text AS ip_address, display_name,
os_family, os_name, arch, agent_version, health_status,
last_health_at, last_patch_at, agent_port, notes,
registered_at, updated_at
registered_at, updated_at,
crl_status, crl_age_seconds, crl_next_update
FROM hosts WHERE id = $1
) h
"#,

43
crates/pm-web/src/routes/status.rs Executable file → Normal file
View File

@ -24,6 +24,16 @@ pub struct FleetStatus {
pub total_pending_patches: i64,
pub hosts_requiring_reboot: i64,
pub compliance_pct: f64,
/// Hosts with CRL status 'valid'.
pub crl_valid: i64,
/// Hosts with CRL status 'expired'.
pub crl_expired: i64,
/// Hosts with CRL status 'missing' (agent reports missing CRL).
pub crl_missing: i64,
/// Hosts with CRL status 'invalid' (security event — needs immediate attention).
pub crl_invalid: i64,
/// Hosts not reporting CRL status (older agents or no data yet).
pub crl_not_reporting: i64,
}
// ── GET /api/v1/status/fleet ──────────────────────────────────────────────────
@ -132,6 +142,34 @@ pub async fn fleet_status(
// Round to one decimal place.
let compliance_pct = (compliance_pct * 10.0).round() / 10.0;
// ── 5. CRL status counts ────────────────────────────────────────────────
let (crl_valid, crl_expired, crl_missing, crl_invalid, crl_not_reporting): (
i64,
i64,
i64,
i64,
i64,
) = sqlx::query_as(
r#"
SELECT
COALESCE(SUM(CASE WHEN crl_status = 'valid' THEN 1 END), 0),
COALESCE(SUM(CASE WHEN crl_status = 'expired' THEN 1 END), 0),
COALESCE(SUM(CASE WHEN crl_status = 'missing' THEN 1 END), 0),
COALESCE(SUM(CASE WHEN crl_status = 'invalid' THEN 1 END), 0),
COALESCE(SUM(CASE WHEN crl_status IS NULL THEN 1 END), 0)
FROM hosts
"#,
)
.fetch_one(&state.db)
.await
.map_err(|e| {
tracing::error!(error = %e, "fleet_status: failed to query CRL status counts");
(
StatusCode::INTERNAL_SERVER_ERROR,
Json(json!({ "error": { "code": "internal_error", "message": "Database error" } })),
)
})?;
Ok(Json(FleetStatus {
total_hosts,
healthy,
@ -141,5 +179,10 @@ pub async fn fleet_status(
total_pending_patches,
hosts_requiring_reboot,
compliance_pct,
crl_valid,
crl_expired,
crl_missing,
crl_invalid,
crl_not_reporting,
}))
}