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    /// Sensitive authorization evidence may only use collision-resistant digests.
37    SensitiveAuthorizationEvidenceRequiresDigest,
38    /// The prepared request requires the evidence-aware plan builder.
39    AuthorizationEvidenceRequired,
40    /// The permit remains valid after its authorization evidence expires.
41    AuthorizationEvidenceValidityMismatch,
42    /// Caller-provided collision-resistant hashing failed.
43    Hasher(E),
44    /// Hasher output length differs from its admitted algorithm.
45    InvalidDigestLength,
46}
47
48impl<E> fmt::Debug for PlanFingerprintBuildError<E> {
49    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
50        formatter.write_str(match self {
51            Self::ReadOnlyOperation => "PlanFingerprintBuildError::ReadOnlyOperation",
52            Self::MissingOperationId => "PlanFingerprintBuildError::MissingOperationId",
53            Self::EndpointNotAdmitted => "PlanFingerprintBuildError::EndpointNotAdmitted",
54            Self::NoOp => "PlanFingerprintBuildError::NoOp",
55            Self::Context(_) => "PlanFingerprintBuildError::Context",
56            Self::MissingCost => "PlanFingerprintBuildError::MissingCost",
57            Self::UnexpectedCost => "PlanFingerprintBuildError::UnexpectedCost",
58            Self::InvalidSingleAttemptBudget => {
59                "PlanFingerprintBuildError::InvalidSingleAttemptBudget"
60            }
61            Self::MissingIdempotency => "PlanFingerprintBuildError::MissingIdempotency",
62            Self::UnexpectedIdempotency => "PlanFingerprintBuildError::UnexpectedIdempotency",
63            Self::InputTooLarge => "PlanFingerprintBuildError::InputTooLarge",
64            Self::OutputTooSmall => "PlanFingerprintBuildError::OutputTooSmall",
65            Self::SensitiveBodyRequiresDigest => {
66                "PlanFingerprintBuildError::SensitiveBodyRequiresDigest"
67            }
68            Self::SensitiveAuthorizationEvidenceRequiresDigest => {
69                "PlanFingerprintBuildError::SensitiveAuthorizationEvidenceRequiresDigest"
70            }
71            Self::AuthorizationEvidenceRequired => {
72                "PlanFingerprintBuildError::AuthorizationEvidenceRequired"
73            }
74            Self::AuthorizationEvidenceValidityMismatch => {
75                "PlanFingerprintBuildError::AuthorizationEvidenceValidityMismatch"
76            }
77            Self::Hasher(_) => "PlanFingerprintBuildError::Hasher([redacted])",
78            Self::InvalidDigestLength => "PlanFingerprintBuildError::InvalidDigestLength",
79        })
80    }
81}
82
83impl<E> fmt::Display for PlanFingerprintBuildError<E> {
84    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
85        formatter.write_str(match self {
86            Self::ReadOnlyOperation => "read-only operation does not accept an execution permit",
87            Self::MissingOperationId => "plan confirmation requires an operation identifier",
88            Self::EndpointNotAdmitted => "plan confirmation endpoint is not admitted",
89            Self::NoOp => "no-op plan cannot receive execution authority",
90            Self::Context(_) => "plan confirmation context is invalid",
91            Self::MissingCost => "cost-bearing plan requires price confirmation",
92            Self::UnexpectedCost => "no-known-cost plan cannot include price authority",
93            Self::InvalidSingleAttemptBudget => "single-attempt plan must authorize one attempt",
94            Self::MissingIdempotency => "reconciliation replay requires idempotency identity",
95            Self::UnexpectedIdempotency => "idempotency identity requires reconciliation replay",
96            Self::InputTooLarge => "canonical plan confirmation exceeds its size limit",
97            Self::OutputTooSmall => "plan confirmation output is too small",
98            Self::SensitiveBodyRequiresDigest => {
99                "sensitive request body requires a collision-resistant plan digest"
100            }
101            Self::SensitiveAuthorizationEvidenceRequiresDigest => {
102                "sensitive authorization evidence requires a collision-resistant plan digest"
103            }
104            Self::AuthorizationEvidenceRequired => {
105                "prepared request requires provider authorization evidence"
106            }
107            Self::AuthorizationEvidenceValidityMismatch => {
108                "permit validity exceeds authorization evidence validity"
109            }
110            Self::Hasher(_) => "plan confirmation hashing failed",
111            Self::InvalidDigestLength => "plan confirmation digest length is invalid",
112        })
113    }
114}
115
116impl<E: core::error::Error + 'static> core::error::Error for PlanFingerprintBuildError<E> {
117    fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
118        match self {
119            Self::Context(error) => Some(error),
120            Self::Hasher(error) => Some(error),
121            _ => None,
122        }
123    }
124}
125
126pub(super) fn map_infallible<E>(
127    error: PlanFingerprintBuildError<core::convert::Infallible>,
128) -> PlanFingerprintBuildError<E> {
129    match error {
130        PlanFingerprintBuildError::ReadOnlyOperation => {
131            PlanFingerprintBuildError::ReadOnlyOperation
132        }
133        PlanFingerprintBuildError::MissingOperationId => {
134            PlanFingerprintBuildError::MissingOperationId
135        }
136        PlanFingerprintBuildError::EndpointNotAdmitted => {
137            PlanFingerprintBuildError::EndpointNotAdmitted
138        }
139        PlanFingerprintBuildError::NoOp => PlanFingerprintBuildError::NoOp,
140        PlanFingerprintBuildError::Context(error) => PlanFingerprintBuildError::Context(error),
141        PlanFingerprintBuildError::MissingCost => PlanFingerprintBuildError::MissingCost,
142        PlanFingerprintBuildError::UnexpectedCost => PlanFingerprintBuildError::UnexpectedCost,
143        PlanFingerprintBuildError::InvalidSingleAttemptBudget => {
144            PlanFingerprintBuildError::InvalidSingleAttemptBudget
145        }
146        PlanFingerprintBuildError::MissingIdempotency => {
147            PlanFingerprintBuildError::MissingIdempotency
148        }
149        PlanFingerprintBuildError::UnexpectedIdempotency => {
150            PlanFingerprintBuildError::UnexpectedIdempotency
151        }
152        PlanFingerprintBuildError::InputTooLarge => PlanFingerprintBuildError::InputTooLarge,
153        PlanFingerprintBuildError::OutputTooSmall => PlanFingerprintBuildError::OutputTooSmall,
154        PlanFingerprintBuildError::SensitiveBodyRequiresDigest => {
155            PlanFingerprintBuildError::SensitiveBodyRequiresDigest
156        }
157        PlanFingerprintBuildError::SensitiveAuthorizationEvidenceRequiresDigest => {
158            PlanFingerprintBuildError::SensitiveAuthorizationEvidenceRequiresDigest
159        }
160        PlanFingerprintBuildError::AuthorizationEvidenceRequired => {
161            PlanFingerprintBuildError::AuthorizationEvidenceRequired
162        }
163        PlanFingerprintBuildError::AuthorizationEvidenceValidityMismatch => {
164            PlanFingerprintBuildError::AuthorizationEvidenceValidityMismatch
165        }
166        PlanFingerprintBuildError::InvalidDigestLength => {
167            PlanFingerprintBuildError::InvalidDigestLength
168        }
169        PlanFingerprintBuildError::Hasher(never) => match never {},
170    }
171}