1use super::{
4 AccountingPosture, AssuranceGenerations, AssuranceLevel, AssuranceToken, CleanupError,
5 CleanupReport, JournalDisposition, LifecyclePosture, PendingStage, PhysicalProtection,
6 ProviderHealth, WipeEvidence,
7};
8use crate::runtime::{CtGatePosture, OperationBackendReport, WipePosture};
9
10#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
12#[non_exhaustive]
13pub enum SecretOperation {
14 NotStarted,
16 Encode,
18 Decode,
20}
21
22impl SecretOperation {
23 #[must_use]
25 pub const fn as_str(self) -> &'static str {
26 match self {
27 Self::NotStarted => "not-started",
28 Self::Encode => "secret-encode",
29 Self::Decode => "secret-decode",
30 }
31 }
32}
33
34#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
36#[non_exhaustive]
37pub enum AttestationPosture {
38 NotAttested,
40 Attested,
42}
43
44impl AttestationPosture {
45 #[must_use]
47 pub const fn as_str(self) -> &'static str {
48 match self {
49 Self::NotAttested => "not-attested",
50 Self::Attested => "attested",
51 }
52 }
53}
54
55#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
57#[non_exhaustive]
58pub enum SecretPolicyPosture {
59 BestEffort,
61 HighAssuranceAttested,
63}
64
65impl SecretPolicyPosture {
66 #[must_use]
68 pub const fn as_str(self) -> &'static str {
69 match self {
70 Self::BestEffort => "best-effort",
71 Self::HighAssuranceAttested => "high-assurance-attested",
72 }
73 }
74}
75
76#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
78#[non_exhaustive]
79pub enum AllocationPosture {
80 Present,
82 Absent,
84 UnknownNoAddressRetained,
86}
87
88impl AllocationPosture {
89 #[must_use]
91 pub const fn as_str(self) -> &'static str {
92 match self {
93 Self::Present => "present",
94 Self::Absent => "absent",
95 Self::UnknownNoAddressRetained => "unknown-no-address-retained",
96 }
97 }
98}
99
100#[derive(Clone, Copy, Debug, Eq, PartialEq)]
102pub struct AssuranceReport {
103 pub encode_backend: OperationBackendReport,
105 pub strict_decode_backend: OperationBackendReport,
107 pub secret_decode_backend: OperationBackendReport,
109 pub generations: AssuranceGenerations,
111 pub wipe_posture: WipePosture,
113 pub result_gate_posture: CtGatePosture,
115 pub attestation_posture: AttestationPosture,
117 pub secret_policy_posture: SecretPolicyPosture,
119 pub wasm_artifact_posture: crate::runtime::WasmArtifactPosture,
121 pub wasm_runtime_posture: crate::runtime::WasmRuntimePosture,
123}
124
125impl AssuranceReport {
126 #[must_use]
128 pub const fn snapshot(self) -> AssuranceSnapshot {
129 AssuranceSnapshot {
130 encode_backend: self.encode_backend.snapshot(),
131 strict_decode_backend: self.strict_decode_backend.snapshot(),
132 secret_decode_backend: self.secret_decode_backend.snapshot(),
133 ordinary_backend_generation: self.generations.ordinary_backend,
134 secret_algorithm_generation: self.generations.secret_algorithm,
135 wipe_barrier_generation: self.generations.wipe_barrier,
136 speculation_generation: self.generations.speculation,
137 wipe_posture: self.wipe_posture.as_str(),
138 result_gate_posture: self.result_gate_posture.as_str(),
139 attestation_posture: self.attestation_posture.as_str(),
140 secret_policy_posture: self.secret_policy_posture.as_str(),
141 wasm_artifact_posture: self.wasm_artifact_posture.as_str(),
142 wasm_runtime_posture: self.wasm_runtime_posture.as_str(),
143 }
144 }
145}
146
147#[derive(Clone, Copy, Debug, Eq, PartialEq)]
149pub struct AssuranceSnapshot {
150 pub encode_backend: crate::runtime::OperationBackendSnapshot,
152 pub strict_decode_backend: crate::runtime::OperationBackendSnapshot,
154 pub secret_decode_backend: crate::runtime::OperationBackendSnapshot,
156 pub ordinary_backend_generation: usize,
158 pub secret_algorithm_generation: usize,
160 pub wipe_barrier_generation: usize,
162 pub speculation_generation: usize,
164 pub wipe_posture: &'static str,
166 pub result_gate_posture: &'static str,
168 pub attestation_posture: &'static str,
170 pub secret_policy_posture: &'static str,
172 pub wasm_artifact_posture: &'static str,
174 pub wasm_runtime_posture: &'static str,
176}
177
178#[derive(Clone, Copy, Debug, Eq, PartialEq)]
180pub struct ProtectedOperationReport {
181 pub assurance: AssuranceReport,
183 pub operation: SecretOperation,
185 pub wipe: WipeEvidence,
187 pub physical_protection: PhysicalProtection,
189 pub accounting: AccountingPosture,
191 pub lifecycle: LifecyclePosture,
193 pub allocation: AllocationPosture,
195 pub provider_health: ProviderHealth,
197 pub health_generation: usize,
199 pub protection_generation: usize,
201}
202
203impl ProtectedOperationReport {
204 pub(crate) const fn live(
205 assurance: AssuranceReport,
206 operation: SecretOperation,
207 physical_protection: PhysicalProtection,
208 provider_health: ProviderHealth,
209 health_generation: usize,
210 protection_generation: usize,
211 ) -> Self {
212 Self {
213 assurance,
214 operation,
215 wipe: WipeEvidence::WipeNotCompleted,
216 physical_protection,
217 accounting: AccountingPosture::Charged,
218 lifecycle: LifecyclePosture::Live,
219 allocation: AllocationPosture::Present,
220 provider_health,
221 health_generation,
222 protection_generation,
223 }
224 }
225
226 #[must_use]
228 pub const fn snapshot(self) -> ProtectedOperationSnapshot {
229 ProtectedOperationSnapshot {
230 assurance: self.assurance.snapshot(),
231 operation: self.operation.as_str(),
232 wipe: wipe_id(self.wipe),
233 physical_protection: physical_id(self.physical_protection),
234 accounting: accounting_id(self.accounting),
235 lifecycle: lifecycle_id(self.lifecycle),
236 allocation: self.allocation.as_str(),
237 provider_health: provider_health_id(self.provider_health),
238 health_generation: self.health_generation,
239 protection_generation: self.protection_generation,
240 }
241 }
242}
243
244#[derive(Clone, Copy, Debug, Eq, PartialEq)]
246pub struct ProtectedOperationSnapshot {
247 pub assurance: AssuranceSnapshot,
249 pub operation: &'static str,
251 pub wipe: &'static str,
253 pub physical_protection: &'static str,
255 pub accounting: &'static str,
257 pub lifecycle: &'static str,
259 pub allocation: &'static str,
261 pub provider_health: &'static str,
263 pub health_generation: usize,
265 pub protection_generation: usize,
267}
268
269#[derive(Clone, Copy, Debug, Eq, PartialEq)]
271pub struct CleanupSnapshot {
272 pub wipe: &'static str,
274 pub physical_protection: &'static str,
276 pub accounting: &'static str,
278 pub lifecycle: &'static str,
280 pub allocation: &'static str,
282 pub pending_stage: Option<&'static str>,
284 pub pending_substage: Option<&'static str>,
286 pub provider_health: Option<&'static str>,
288 pub retry_attempt: Option<usize>,
290}
291
292#[derive(Clone, Copy, Debug, Eq, PartialEq)]
294pub struct ProviderSnapshot {
295 pub health: &'static str,
297 pub health_generation: usize,
299 pub protection_generation: usize,
301 pub active_and_reserved: usize,
303 pub quarantined: usize,
305 pub permanently_quarantined: usize,
307 pub tombstoned: usize,
309 pub charged_logical_bytes: usize,
311 pub charged_effective_pages: usize,
313}
314
315impl super::ProviderReport {
316 #[must_use]
318 pub const fn snapshot(self) -> ProviderSnapshot {
319 ProviderSnapshot {
320 health: provider_health_id(self.health),
321 health_generation: self.health_generation,
322 protection_generation: self.protection_generation,
323 active_and_reserved: self.active_and_reserved,
324 quarantined: self.quarantined,
325 permanently_quarantined: self.permanently_quarantined,
326 tombstoned: self.tombstoned,
327 charged_logical_bytes: self.charged_logical_bytes,
328 charged_effective_pages: self.charged_effective_pages,
329 }
330 }
331}
332
333impl<Level: AssuranceLevel> AssuranceToken<'_, Level> {
334 #[must_use]
336 pub fn report(&self) -> AssuranceReport {
337 let runtime = crate::runtime::backend_report();
338 let mut encode_backend = runtime.encode_backend;
339 let mut strict_decode_backend = runtime.strict_decode_backend;
340 let mut secret_decode_backend = runtime.secret_decode_backend;
341 let generations = self.generations();
342 encode_backend.health_generation = generations.ordinary_backend;
343 strict_decode_backend.health_generation = generations.ordinary_backend;
344 secret_decode_backend.health_generation = generations.secret_algorithm;
345 let evidence = self.evidence();
346 AssuranceReport {
347 encode_backend,
348 strict_decode_backend,
349 secret_decode_backend,
350 generations,
351 wipe_posture: evidence.map_or(
352 runtime.wipe_posture,
353 super::context::AttestationEvidence::wipe_posture,
354 ),
355 result_gate_posture: evidence.map_or(
356 runtime.ct_gate_posture,
357 super::context::AttestationEvidence::speculation_posture,
358 ),
359 attestation_posture: if evidence.is_some() {
360 AttestationPosture::Attested
361 } else {
362 AttestationPosture::NotAttested
363 },
364 secret_policy_posture: if Self::requires_attestation() {
365 SecretPolicyPosture::HighAssuranceAttested
366 } else {
367 SecretPolicyPosture::BestEffort
368 },
369 wasm_artifact_posture: runtime.wasm_artifact_posture,
370 wasm_runtime_posture: runtime.wasm_runtime_posture,
371 }
372 }
373}
374
375impl CleanupReport {
376 #[must_use]
378 pub const fn snapshot(self) -> CleanupSnapshot {
379 CleanupSnapshot {
380 wipe: wipe_id(self.wipe),
381 physical_protection: physical_id(self.physical_protection),
382 accounting: accounting_id(self.accounting),
383 lifecycle: lifecycle_id(self.lifecycle),
384 allocation: AllocationPosture::Absent.as_str(),
385 pending_stage: None,
386 pending_substage: None,
387 provider_health: None,
388 retry_attempt: None,
389 }
390 }
391}
392
393impl CleanupError {
394 #[must_use]
396 pub const fn snapshot(self) -> CleanupSnapshot {
397 let allocation = if matches!(self.lifecycle, LifecyclePosture::Tombstoned { .. }) {
398 AllocationPosture::UnknownNoAddressRetained
399 } else {
400 AllocationPosture::Present
401 };
402 CleanupSnapshot {
403 wipe: wipe_id(self.wipe),
404 physical_protection: physical_id(self.physical_protection),
405 accounting: accounting_id(self.accounting),
406 lifecycle: lifecycle_id(self.lifecycle),
407 allocation: allocation.as_str(),
408 pending_stage: Some(pending_stage_id(self.pending_stage)),
409 pending_substage: Some(journal_id(self.pending_substage)),
410 provider_health: Some(provider_health_id(self.provider_health)),
411 retry_attempt: Some(self.retry_attempt),
412 }
413 }
414}
415
416const fn wipe_id(value: WipeEvidence) -> &'static str {
417 match value {
418 WipeEvidence::WipeNotCompleted => "wipe-not-completed",
419 WipeEvidence::WipedBestEffort => "wiped-best-effort",
420 WipeEvidence::WipedAttested => "wiped-attested",
421 }
422}
423
424const fn physical_id(value: PhysicalProtection) -> &'static str {
425 match value {
426 PhysicalProtection::ProtectionAttested => "protection-attested",
427 PhysicalProtection::ProtectionConfirmedAbsent => "protection-confirmed-absent",
428 PhysicalProtection::ProtectionUnknown => "protection-unknown",
429 }
430}
431
432const fn accounting_id(value: AccountingPosture) -> &'static str {
433 match value {
434 AccountingPosture::Charged => "charged",
435 AccountingPosture::Reconciled => "reconciled",
436 }
437}
438
439const fn lifecycle_id(value: LifecyclePosture) -> &'static str {
440 match value {
441 LifecyclePosture::Live => "live",
442 LifecyclePosture::Closing { .. } => "closing",
443 LifecyclePosture::Quarantined { .. } => "quarantined",
444 LifecyclePosture::PermanentlyQuarantined { .. } => "permanently-quarantined",
445 LifecyclePosture::Tombstoned { .. } => "tombstoned",
446 LifecyclePosture::Closed => "closed",
447 }
448}
449
450const fn pending_stage_id(value: PendingStage) -> &'static str {
451 match value {
452 PendingStage::Wipe => "wipe",
453 PendingStage::ProtectionRemoval => "protection-removal",
454 PendingStage::AccountingReconciliation => "accounting-reconciliation",
455 PendingStage::Disposal => "disposal",
456 }
457}
458
459const fn journal_id(value: JournalDisposition) -> &'static str {
460 match value {
461 JournalDisposition::NotApplied => "not-applied",
462 JournalDisposition::Applied => "applied",
463 JournalDisposition::Indeterminate => "indeterminate",
464 }
465}
466
467const fn provider_health_id(value: ProviderHealth) -> &'static str {
468 match value {
469 ProviderHealth::Healthy => "healthy",
470 ProviderHealth::Degraded => "degraded",
471 ProviderHealth::Exhausted => "exhausted",
472 ProviderHealth::Shutdown => "shutdown",
473 }
474}