Skip to main content

cloud_sdk/operation/permit/fingerprint/
error.rs

1//! Payload-redacting plan-confirm construction errors.
2
3use core::fmt;
4
5use crate::operation::PermitContextError;
6
7/// Plan-confirm construction failure.
8#[derive(Clone, Copy)]
9pub enum PlanFingerprintBuildError<E> {
10    /// Read-only requests do not accept state-change permits.
11    ReadOnlyOperation,
12    /// The prepared request has no provider operation identifier.
13    MissingOperationId,
14    /// The endpoint is outside the provider-owned trust policy.
15    EndpointNotAdmitted,
16    /// Caller marked the plan as an ineffective no-op.
17    NoOp,
18    /// An account, tenant, or context value is invalid.
19    Context(PermitContextError),
20    /// Cost metadata is required by operation policy.
21    MissingCost,
22    /// Cost metadata was supplied for a no-known-cost operation.
23    UnexpectedCost,
24    /// Single-attempt policy must have an exact budget of one.
25    InvalidSingleAttemptBudget,
26    /// Reconciliation policy requires an idempotency identity.
27    MissingIdempotency,
28    /// Identity is forbidden when reconciliation is not admitted.
29    UnexpectedIdempotency,
30    /// Canonical length arithmetic overflowed or exceeded the hard bound.
31    InputTooLarge,
32    /// Caller output cannot hold the complete canonical input or digest.
33    OutputTooSmall,
34    /// Sensitive request bodies may only use collision-resistant digests.
35    SensitiveBodyRequiresDigest,
36    /// Caller-provided collision-resistant hashing failed.
37    Hasher(E),
38    /// Hasher output length differs from its admitted algorithm.
39    InvalidDigestLength,
40}
41
42impl<E> fmt::Debug for PlanFingerprintBuildError<E> {
43    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
44        formatter.write_str(match self {
45            Self::ReadOnlyOperation => "PlanFingerprintBuildError::ReadOnlyOperation",
46            Self::MissingOperationId => "PlanFingerprintBuildError::MissingOperationId",
47            Self::EndpointNotAdmitted => "PlanFingerprintBuildError::EndpointNotAdmitted",
48            Self::NoOp => "PlanFingerprintBuildError::NoOp",
49            Self::Context(_) => "PlanFingerprintBuildError::Context",
50            Self::MissingCost => "PlanFingerprintBuildError::MissingCost",
51            Self::UnexpectedCost => "PlanFingerprintBuildError::UnexpectedCost",
52            Self::InvalidSingleAttemptBudget => {
53                "PlanFingerprintBuildError::InvalidSingleAttemptBudget"
54            }
55            Self::MissingIdempotency => "PlanFingerprintBuildError::MissingIdempotency",
56            Self::UnexpectedIdempotency => "PlanFingerprintBuildError::UnexpectedIdempotency",
57            Self::InputTooLarge => "PlanFingerprintBuildError::InputTooLarge",
58            Self::OutputTooSmall => "PlanFingerprintBuildError::OutputTooSmall",
59            Self::SensitiveBodyRequiresDigest => {
60                "PlanFingerprintBuildError::SensitiveBodyRequiresDigest"
61            }
62            Self::Hasher(_) => "PlanFingerprintBuildError::Hasher([redacted])",
63            Self::InvalidDigestLength => "PlanFingerprintBuildError::InvalidDigestLength",
64        })
65    }
66}
67
68impl<E> fmt::Display for PlanFingerprintBuildError<E> {
69    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
70        formatter.write_str(match self {
71            Self::ReadOnlyOperation => "read-only operation does not accept an execution permit",
72            Self::MissingOperationId => "plan confirmation requires an operation identifier",
73            Self::EndpointNotAdmitted => "plan confirmation endpoint is not admitted",
74            Self::NoOp => "no-op plan cannot receive execution authority",
75            Self::Context(_) => "plan confirmation context is invalid",
76            Self::MissingCost => "cost-bearing plan requires price confirmation",
77            Self::UnexpectedCost => "no-known-cost plan cannot include price authority",
78            Self::InvalidSingleAttemptBudget => "single-attempt plan must authorize one attempt",
79            Self::MissingIdempotency => "reconciliation replay requires idempotency identity",
80            Self::UnexpectedIdempotency => "idempotency identity requires reconciliation replay",
81            Self::InputTooLarge => "canonical plan confirmation exceeds its size limit",
82            Self::OutputTooSmall => "plan confirmation output is too small",
83            Self::SensitiveBodyRequiresDigest => {
84                "sensitive request body requires a collision-resistant plan digest"
85            }
86            Self::Hasher(_) => "plan confirmation hashing failed",
87            Self::InvalidDigestLength => "plan confirmation digest length is invalid",
88        })
89    }
90}
91
92impl<E: core::error::Error + 'static> core::error::Error for PlanFingerprintBuildError<E> {
93    fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
94        match self {
95            Self::Context(error) => Some(error),
96            Self::Hasher(error) => Some(error),
97            _ => None,
98        }
99    }
100}
101
102pub(super) fn map_infallible<E>(
103    error: PlanFingerprintBuildError<core::convert::Infallible>,
104) -> PlanFingerprintBuildError<E> {
105    match error {
106        PlanFingerprintBuildError::ReadOnlyOperation => {
107            PlanFingerprintBuildError::ReadOnlyOperation
108        }
109        PlanFingerprintBuildError::MissingOperationId => {
110            PlanFingerprintBuildError::MissingOperationId
111        }
112        PlanFingerprintBuildError::EndpointNotAdmitted => {
113            PlanFingerprintBuildError::EndpointNotAdmitted
114        }
115        PlanFingerprintBuildError::NoOp => PlanFingerprintBuildError::NoOp,
116        PlanFingerprintBuildError::Context(error) => PlanFingerprintBuildError::Context(error),
117        PlanFingerprintBuildError::MissingCost => PlanFingerprintBuildError::MissingCost,
118        PlanFingerprintBuildError::UnexpectedCost => PlanFingerprintBuildError::UnexpectedCost,
119        PlanFingerprintBuildError::InvalidSingleAttemptBudget => {
120            PlanFingerprintBuildError::InvalidSingleAttemptBudget
121        }
122        PlanFingerprintBuildError::MissingIdempotency => {
123            PlanFingerprintBuildError::MissingIdempotency
124        }
125        PlanFingerprintBuildError::UnexpectedIdempotency => {
126            PlanFingerprintBuildError::UnexpectedIdempotency
127        }
128        PlanFingerprintBuildError::InputTooLarge => PlanFingerprintBuildError::InputTooLarge,
129        PlanFingerprintBuildError::OutputTooSmall => PlanFingerprintBuildError::OutputTooSmall,
130        PlanFingerprintBuildError::SensitiveBodyRequiresDigest => {
131            PlanFingerprintBuildError::SensitiveBodyRequiresDigest
132        }
133        PlanFingerprintBuildError::InvalidDigestLength => {
134            PlanFingerprintBuildError::InvalidDigestLength
135        }
136        PlanFingerprintBuildError::Hasher(never) => match never {},
137    }
138}