Skip to main content

max / makenotwork

3.0 KB · 90 lines History Blame Raw
1 //! Local CA-bundle freshness alert/recovery messages. Domain half of the
2 //! Alerter split; shared dispatch/cooldown plumbing lives in the parent module.
3
4 use tracing::instrument;
5
6 use super::{AlertCategory, AlertMeta, Alerter};
7
8 impl Alerter {
9 /// Fire when a host's trust-anchor bundle transitions out of `ok`. Carries
10 /// the issue lines that fired, which say which of the three signals tripped.
11 #[instrument(skip_all)]
12 pub async fn send_ca_bundle_alert(
13 &self,
14 target: &str,
15 label: &str,
16 status: &str,
17 issues: &[String],
18 ) {
19 let alert_key = format!("ca_bundle:{target}");
20 let subject = format!("[PoM] {label}: CA bundle {status}");
21 let body = format!(
22 "Target: {label} ({target})\n\
23 Status: {status}\n\
24 Issues:\n{}\n\
25 Instance: {}\n\
26 Time: {}\n\n\
27 Every outbound TLS client on this host reads its trust anchors from\n\
28 this bundle, and multithreaded has no in-binary roots to fall back on.\n\n\
29 - PoM",
30 issues
31 .iter()
32 .map(|i| format!(" - {i}"))
33 .collect::<Vec<_>>()
34 .join("\n"),
35 self.instance_name,
36 chrono::Utc::now().to_rfc3339(),
37 );
38
39 // `thin` means the bundle cannot validate the public web PKI any more,
40 // so outbound TLS is either broken now or one handshake away from it.
41 // `stale` and `unknown` are drift: worth a ticket, not worth a page.
42 let priority = if status == "thin" { "critical" } else { "high" };
43 self.fire_failure(
44 &subject,
45 &body,
46 priority,
47 "pom-ca-bundle",
48 Some(target),
49 AlertMeta {
50 key: &alert_key,
51 category: AlertCategory::CaBundleStale,
52 from: None,
53 to: Some(status),
54 error: None,
55 },
56 )
57 .await;
58 }
59
60 /// Fire on recovery: the package is current, the lists are fresh, and the
61 /// bundle holds a plausible number of certificates again.
62 #[instrument(skip_all)]
63 pub async fn send_ca_bundle_recovery(&self, target: &str, label: &str) {
64 let alert_key = format!("ca_bundle:{target}");
65 let subject = format!("[PoM] {label}: CA bundle current");
66 let body = format!(
67 "Target: {label} ({target})\n\
68 The host trust-anchor bundle is current.\n\
69 Instance: {}\n\
70 Time: {}\n\n\
71 - PoM",
72 self.instance_name,
73 chrono::Utc::now().to_rfc3339(),
74 );
75
76 self.fire_recovery(
77 &subject,
78 &body,
79 AlertMeta {
80 key: &alert_key,
81 category: AlertCategory::CaBundleRecovery,
82 from: None,
83 to: Some("ok"),
84 error: None,
85 },
86 )
87 .await;
88 }
89 }
90