coven_replication/sync/store/membership/
mod.rs1use coven_keys::keys::KeyError;
7use coven_protocol::objects::StorageError;
8use coven_protocol::objects::StoreObjectError;
9use coven_storage::CloudHomeJoinInfo;
10use serde::{Deserialize, Serialize};
11
12#[derive(Clone, Serialize, Deserialize, Debug)]
13#[serde(deny_unknown_fields)]
14pub struct MemberAdmission {
15 pub store_id: String,
16 pub store_name: String,
17 pub join_info: CloudHomeJoinInfo,
18 pub owner_pubkey: String,
19 pub wrapped_key: coven_protocol::wrapped_store_key::WrappedStoreKeyRef,
20 pub store_root: coven_protocol::store_commit::StoreRootRef,
21 pub membership_floor: coven_protocol::membership::MembershipFloor,
22}
23
24#[derive(Debug, thiserror::Error)]
32pub enum MembershipOpsError {
33 #[error("membership storage error: {0}")]
34 Storage(#[from] StorageError),
35 #[error("Store protocol object error: {0}")]
36 StoreObject(#[from] coven_protocol::objects::StoreObjectError),
37 #[error("membership database state error: {0}")]
38 Database(#[from] coven_database::DbError),
39 #[error("Store access failed: {0}")]
40 Store(#[from] crate::sync::store::StoreError),
41 #[error("{0}")]
42 Chain(#[from] AnchoredChainError),
43 #[error("{0}")]
44 Mutation(#[from] MembershipMutationError),
45 #[error(
49 "member removal committed the cloud key rotation, but this device could not \
50 adopt the rotated key locally: {source}; retry the same removal"
51 )]
52 RotationCommittedAdoptionFailed {
53 #[source]
54 source: KeyError,
55 },
56 #[error("cannot admit this device as a new member")]
57 SelfAdmission,
58 #[error("the identity is already a member with different role or provider account")]
59 ExistingMemberMismatch,
60 #[error("the existing member does not have exactly one current wrapped Store key")]
61 ExistingMemberKeyAuthority,
62 #[error(
66 "no membership chain to admit into: the store's founder entry is \
67 missing (it is established at store creation)"
68 )]
69 NoFounderChainForAdmission,
70 #[error("membership chain has no founder")]
71 ChainHasNoFounder,
72 #[error("sharing requires an encrypted cloud home")]
73 NotEncryptedHome,
74}
75
76mod mutation;
77
78#[derive(Debug, thiserror::Error)]
80pub enum AnchoredChainError {
81 #[error("membership authority transition is awaiting publication finalization: {source}")]
82 IncompleteFinalization {
83 head: Box<coven_protocol::membership::MembershipHeadRef>,
84 #[source]
85 source: StorageError,
86 },
87 #[error("membership storage unavailable while {operation}: {source}")]
88 StorageUnavailable {
89 operation: String,
90 #[source]
91 source: StorageError,
92 },
93 #[error("membership chain failed to load/validate: {0}")]
94 LoadFailed(String),
95 #[error("membership object: {0}")]
96 Object(#[from] StoreObjectError),
97 #[error("membership database: {0}")]
98 Database(#[from] coven_database::DbError),
99 #[error("membership protocol: {0}")]
100 Membership(#[from] coven_protocol::membership::MembershipError),
101 #[error("membership Store publication: {0}")]
102 StoreProtocol(#[from] coven_protocol::store_commit::StoreProtocolError),
103 #[error("membership provider probe: {0}")]
104 ProviderProbe(#[from] coven_protocol::provider::ProviderProbeError),
105 #[error("membership floor failed validation: {0}")]
106 InvalidFloor(#[from] coven_protocol::membership::MembershipFloorError),
107 #[error("membership Store pull: {0}")]
108 StorePull(#[source] Box<crate::sync::store::StorePullError>),
109 #[error("chain founder {founder:?} is not the pinned owner {owner}")]
110 FounderMismatch {
111 founder: Option<String>,
112 owner: String,
113 },
114}
115
116impl From<crate::sync::store::StorePullError> for AnchoredChainError {
117 fn from(error: crate::sync::store::StorePullError) -> Self {
118 Self::StorePull(Box::new(error))
119 }
120}
121
122impl AnchoredChainError {
123 pub(crate) fn from_store_object(error: StoreObjectError) -> Self {
124 match error {
125 StoreObjectError::Storage(source @ StorageError::Storage(_))
126 | StoreObjectError::Storage(source @ StorageError::RotationPending(_)) => {
127 Self::StorageUnavailable {
128 operation: "discovering immutable membership objects".to_string(),
129 source,
130 }
131 }
132 error => Self::Object(error),
133 }
134 }
135}
136
137pub use mutation::MembershipMutationError;
138
139#[cfg(test)]
140mod tests;