1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
//! Error types for the capability engine.
use crate::resolver::ResolverError;
use crate::types::{ExposureLabel, ObjectId, Operation};
use thiserror::Error;
/// Errors from the capability engine.
#[derive(Error, Debug)]
pub enum EngineError {
/// Capability request denied by policy.
#[error("capability denied: {subject} cannot perform '{operation}' on '{target}': {reason}")]
CapabilityDenied {
subject: ObjectId,
target: ObjectId,
operation: Operation,
reason: String,
},
/// Capability request denied due to exposure restriction.
#[error("capability denied by exposure: label '{label}' blocks access to '{target}'")]
ExposureRestriction {
label: ExposureLabel,
target: ObjectId,
},
/// Identity token operation failed.
#[error("identity error: {0}")]
Identity(String),
/// Context token operation failed.
#[error("context error: {0}")]
Context(String),
/// Token error from underlying token crate.
#[error("token error: {0}")]
Token(#[from] hessra_token_core::TokenError),
/// Token creation or verification failed.
#[error("token operation failed: {0}")]
TokenOperation(String),
/// Policy backend error.
#[error("policy error: {0}")]
Policy(String),
/// A required designation declared in the schema was not supplied at mint
/// time (neither by the policy declaration nor by the caller).
#[error("missing required designation '{label}' for target '{target}' operation '{operation}'")]
MissingRequiredDesignation {
target: ObjectId,
operation: Operation,
label: String,
},
/// A static designation declared in policy references a label that does
/// not appear in the target's schema for the matched operation.
/// Surfaced at engine construction.
#[error(
"policy declares static designation '{label}' for target '{target}' operation '{operation}', but the schema does not declare that label"
)]
UnknownLabelInPolicy {
target: ObjectId,
operation: Operation,
label: String,
},
/// Cross-validation between policy and schema failed at engine construction.
/// Either a policy-declared static designation references an unknown label
/// (see [`EngineError::UnknownLabelInPolicy`]) or another structural
/// mismatch was detected.
#[error("schema/policy mismatch: {0}")]
SchemaPolicyMismatch(String),
/// A designation resolver failed during a `mint_with_context` call.
#[error("resolver error: {0}")]
Resolver(#[from] ResolverError),
/// The mint failed the delegated identity chain check: an ancestor of
/// `subject` either does not hold a grant for `(target, operation)`, or
/// holds a grant whose static designations are not all present in the
/// capability being minted. This enforces "sub-identity capabilities ⊆
/// parent identity capabilities" transitively, including the per-grant
/// designation envelope.
#[error(
"chain check failed: ancestor '{ancestor}' of '{subject}' does not encompass '{operation}' on '{target}': {reason}"
)]
ChainCheckFailed {
subject: ObjectId,
ancestor: ObjectId,
target: ObjectId,
operation: Operation,
reason: ChainCheckFailure,
},
}
/// Why the chain check rejected a mint.
#[derive(Debug, Clone, thiserror::Error)]
pub enum ChainCheckFailure {
/// The ancestor has no grant for the requested target+operation.
#[error("no grant for target/operation")]
NoGrant,
/// The ancestor has a grant for the requested target+operation, but it
/// carries a static designation that the cap being minted does not
/// include (or carries with a different value). The cap would therefore
/// exceed the ancestor's envelope on that label.
#[error(
"ancestor grant requires designation '{label}'='{value}' which the minted cap does not include"
)]
DesignationNotCovered { label: String, value: String },
}