Skip to main content

base64_ng/v2/assurance/
posture.rs

1//! Redacted assurance, provider, and teardown state.
2
3/// Strength of the completed logical-allocation wipe.
4#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
5#[non_exhaustive]
6pub enum WipeEvidence {
7    /// No policy-usable complete overwrite is known.
8    WipeNotCompleted,
9    /// The full logical range and best-effort barrier completed.
10    WipedBestEffort,
11    /// Best-effort wiping completed with current matching platform evidence.
12    WipedAttested,
13}
14
15/// Physical protection independently reported by the provider.
16#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
17#[non_exhaustive]
18pub enum PhysicalProtection {
19    /// Current evidence confirms the requested protection.
20    ProtectionAttested,
21    /// Current evidence conclusively says protection is absent.
22    ProtectionConfirmedAbsent,
23    /// The provider cannot currently establish physical posture.
24    ProtectionUnknown,
25}
26
27/// Conservative provider accounting posture.
28#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
29#[non_exhaustive]
30pub enum AccountingPosture {
31    /// The identity, bytes, and effective pages remain charged.
32    Charged,
33    /// All accounting transitions completed conclusively.
34    Reconciled,
35}
36
37/// Ordered teardown stage that remains incomplete.
38#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
39#[non_exhaustive]
40pub enum PendingStage {
41    /// Complete logical-range wipe and barrier.
42    Wipe,
43    /// Protection removal or page unlock.
44    ProtectionRemoval,
45    /// Provider accounting reconciliation.
46    AccountingReconciliation,
47    /// Conclusive disposal or deallocation.
48    Disposal,
49}
50
51/// Redacted allocation lifecycle posture.
52#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
53#[non_exhaustive]
54pub enum LifecyclePosture {
55    /// One public protected owner is live.
56    Live,
57    /// A consuming teardown is executing.
58    Closing {
59        /// Stage currently executing.
60        stage: PendingStage,
61    },
62    /// Provider quarantine owns an incomplete teardown.
63    Quarantined {
64        /// Earliest stage that must resume.
65        pending_stage: PendingStage,
66    },
67    /// Retry limits were exhausted and in-process recovery is forbidden.
68    PermanentlyQuarantined {
69        /// Earliest permanently incomplete stage.
70        pending_stage: PendingStage,
71    },
72    /// Allocation existence became indeterminate and no pointer remains.
73    Tombstoned {
74        /// Last operation attempted before addressability was destroyed.
75        last_stage: PendingStage,
76        /// Conservative allocation-presence disposition.
77        disposition: AllocationPresence,
78    },
79    /// Teardown completed and no allocation capability remains.
80    Closed,
81}
82
83/// Terminal allocation-presence result used by tombstones.
84#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
85#[non_exhaustive]
86pub enum AllocationPresence {
87    /// The provider cannot establish whether disposal occurred.
88    Unknown,
89}
90
91/// Provider-wide admission health.
92#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
93#[non_exhaustive]
94pub enum ProviderHealth {
95    /// New protected admission is permitted.
96    Healthy,
97    /// A failure blocks new high-assurance admission.
98    Degraded,
99    /// A finite provider budget is exhausted.
100    Exhausted,
101    /// The provider instance cannot admit or recover more work.
102    Shutdown,
103}
104
105/// Finite provider resource category.
106#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
107#[non_exhaustive]
108pub enum ResourceKind {
109    /// Combined active, reserved, quarantined, and tombstoned identities.
110    Identities,
111    /// Complete logical allocation bytes.
112    LogicalBytes,
113    /// Effective page-rounded storage.
114    EffectivePages,
115    /// Pre-reserved quarantine registry slots.
116    RegistryEntries,
117    /// Lifetime retry attempts.
118    RetryAttempts,
119    /// Work permitted in one maintenance call.
120    MaintenanceWork,
121}
122
123/// Finite provider configuration.
124#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
125pub struct ProviderLimits {
126    /// Maximum combined identities.
127    pub max_identities: usize,
128    /// Maximum combined logical bytes.
129    pub max_logical_bytes: usize,
130    /// Maximum combined effective pages.
131    pub max_effective_pages: usize,
132    /// Maximum pre-reserved registry entries.
133    pub max_registry_entries: usize,
134    /// Maximum retry attempts per quarantined identity.
135    pub max_retry_attempts: usize,
136    /// Maximum entries examined by one maintenance call.
137    pub max_maintenance_work: usize,
138    /// Provider page size used for checked reservations.
139    pub page_size: usize,
140}
141
142/// Allocation admission request made before plaintext can materialize.
143#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
144pub struct ProtectionRequest {
145    logical_bytes: usize,
146    reserved_pages: usize,
147    attested: bool,
148}
149
150impl ProtectionRequest {
151    pub(crate) fn new(
152        logical_bytes: usize,
153        page_size: usize,
154        attested: bool,
155    ) -> Result<Self, ProtectionError> {
156        if page_size == 0 {
157            return Err(ProtectionError::InvalidLimits);
158        }
159        let reserved_pages = if logical_bytes == 0 {
160            0
161        } else {
162            logical_bytes
163                .checked_add(page_size - 1)
164                .and_then(|len| len.checked_add(page_size - 1))
165                .map(|worst_case| worst_case / page_size)
166                .ok_or(ProtectionError::LengthOverflow)?
167        };
168        Ok(Self {
169            logical_bytes,
170            reserved_pages,
171            attested,
172        })
173    }
174
175    /// Requested logical allocation bytes.
176    #[must_use]
177    pub const fn logical_bytes(self) -> usize {
178        self.logical_bytes
179    }
180
181    /// Conservatively reserved effective pages.
182    #[must_use]
183    pub const fn reserved_pages(self) -> usize {
184        self.reserved_pages
185    }
186
187    /// Whether the operation requires attested protection.
188    #[must_use]
189    pub const fn requires_attestation(self) -> bool {
190        self.attested
191    }
192}
193
194/// Redacted protected-allocation admission failure.
195#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
196#[non_exhaustive]
197pub enum ProtectionError {
198    /// Policy or attestation evidence is stale or mismatched.
199    StaleAssurance,
200    /// Required physical protection is unavailable.
201    ProtectionUnavailable,
202    /// The provider is not healthy enough for admission.
203    ProviderUnavailable,
204    /// A finite provider resource is exhausted.
205    ProtectionResourceExhausted(ResourceKind),
206    /// Length or page rounding overflowed.
207    LengthOverflow,
208    /// Provider limits are internally invalid.
209    InvalidLimits,
210    /// Actual protected pages exceeded the preflight reservation.
211    ActualRangeExceededReservation,
212}
213
214impl core::fmt::Display for ProtectionError {
215    fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
216        formatter.write_str(match self {
217            Self::StaleAssurance => "stale assurance evidence",
218            Self::ProtectionUnavailable => "required protected storage is unavailable",
219            Self::ProviderUnavailable => "protected-memory provider is unavailable",
220            Self::ProtectionResourceExhausted(_) => "protected-memory resource exhausted",
221            Self::LengthOverflow => "protected-memory length overflow",
222            Self::InvalidLimits => "invalid protected-memory limits",
223            Self::ActualRangeExceededReservation => {
224                "actual protected range exceeded its reservation"
225            }
226        })
227    }
228}
229
230#[cfg(feature = "std")]
231impl std::error::Error for ProtectionError {}
232
233/// One provider sub-operation recorded by the volatile journal.
234#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
235#[non_exhaustive]
236pub enum TeardownOperation {
237    /// Complete wipe confirmation.
238    Wipe,
239    /// Physical protection removal.
240    ProtectionRemoval,
241    /// Accounting reconciliation.
242    AccountingReconciliation,
243    /// Disposal or deallocation.
244    Disposal,
245}
246
247/// Monotonic provider-operation disposition.
248#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
249#[non_exhaustive]
250pub enum JournalDisposition {
251    /// The operation is conclusively not applied.
252    NotApplied,
253    /// The operation is conclusively applied.
254    Applied,
255    /// The provider cannot determine whether it applied.
256    Indeterminate,
257}
258
259/// Fixed-size volatile teardown journal cursor.
260#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
261pub struct TeardownCursor {
262    /// Current operation.
263    pub operation: TeardownOperation,
264    /// Current operation disposition.
265    pub disposition: JournalDisposition,
266    /// Bounded range/page progress cursor.
267    pub progress: usize,
268}
269
270impl TeardownCursor {
271    pub(crate) const fn new() -> Self {
272        Self {
273            operation: TeardownOperation::Wipe,
274            disposition: JournalDisposition::NotApplied,
275            progress: 0,
276        }
277    }
278
279    pub(crate) fn begin(&mut self, operation: TeardownOperation) {
280        self.operation = operation;
281        self.disposition = JournalDisposition::NotApplied;
282        self.progress = 0;
283    }
284}
285
286/// Conclusive or ambiguous disposal result.
287#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
288#[non_exhaustive]
289pub enum DisposalDisposition {
290    /// Disposal completed exactly once.
291    Applied,
292    /// Disposal conclusively did not occur.
293    NotApplied,
294    /// Allocation presence is no longer knowable.
295    AllocationPresenceUnknown,
296}
297
298/// Redacted successful teardown outcome.
299#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
300#[non_exhaustive]
301pub enum CleanupOutcome {
302    /// Every required stage completed.
303    Closed,
304}
305
306/// Redacted successful close report.
307#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
308pub struct CleanupReport {
309    /// Final cleanup outcome.
310    pub outcome: CleanupOutcome,
311    /// Wipe evidence established before close.
312    pub wipe: WipeEvidence,
313    /// Final physical protection posture.
314    pub physical_protection: PhysicalProtection,
315    /// Final accounting posture.
316    pub accounting: AccountingPosture,
317    /// Final lifecycle posture.
318    pub lifecycle: LifecyclePosture,
319}
320
321/// Redacted cleanup failure after ownership transferred to the provider.
322#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
323pub struct CleanupError {
324    /// Earliest stage that remains incomplete.
325    pub pending_stage: PendingStage,
326    /// Strongest wipe evidence actually established.
327    pub wipe: WipeEvidence,
328    /// Last honest physical protection posture.
329    pub physical_protection: PhysicalProtection,
330    /// Conservative accounting posture.
331    pub accounting: AccountingPosture,
332    /// Provider-owned terminal lifecycle.
333    pub lifecycle: LifecyclePosture,
334    /// Redacted provider journal disposition at the pending stage.
335    pub pending_substage: JournalDisposition,
336    /// Retry attempt charged by the transfer.
337    pub retry_attempt: usize,
338    /// Provider health after the failure.
339    pub provider_health: ProviderHealth,
340}
341
342impl core::fmt::Display for CleanupError {
343    fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
344        write!(
345            formatter,
346            "protected cleanup stopped at {:?}",
347            self.pending_stage
348        )
349    }
350}
351
352#[cfg(feature = "std")]
353impl std::error::Error for CleanupError {}
354
355/// Aggregate redacted provider report.
356#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
357pub struct ProviderReport {
358    /// Current provider health.
359    pub health: ProviderHealth,
360    /// Current health generation.
361    pub health_generation: usize,
362    /// Current protection generation.
363    pub protection_generation: usize,
364    /// Combined active and reserved identities.
365    pub active_and_reserved: usize,
366    /// Quarantined identities.
367    pub quarantined: usize,
368    /// Identities whose bounded retry budget is permanently exhausted.
369    pub permanently_quarantined: usize,
370    /// Terminal tombstone identities.
371    pub tombstoned: usize,
372    /// Conservatively charged logical bytes.
373    pub charged_logical_bytes: usize,
374    /// Conservatively charged effective pages.
375    pub charged_effective_pages: usize,
376}