appcore_capabilities/
catalog.rs1use crate::policy::enforce_requirements;
12use crate::{CapabilityError, CapabilityRequest, CapabilityResult};
13use appcore_contracts::ServiceId;
14use appcore_core::{CapabilityDescriptor, CapabilityName, CoreIdentity};
15use appcore_distributed_contracts::ServiceLeadershipGuard;
16use std::collections::HashMap;
17
18pub struct CapabilityEnforcementContext<'a> {
20 pub(crate) identity: &'a CoreIdentity,
21 pub(crate) service_id: &'a ServiceId,
22 pub(crate) leadership: Option<&'a dyn ServiceLeadershipGuard>,
23 pub(crate) now_ms: u64,
24 pub(crate) writes_allowed: bool,
25}
26
27impl<'a> CapabilityEnforcementContext<'a> {
28 pub fn new(identity: &'a CoreIdentity, service_id: &'a ServiceId, now_ms: u64) -> Self {
30 Self {
31 identity,
32 service_id,
33 leadership: None,
34 now_ms,
35 writes_allowed: true,
36 }
37 }
38
39 pub fn with_leadership(mut self, leadership: &'a dyn ServiceLeadershipGuard) -> Self {
41 self.leadership = Some(leadership);
42 self
43 }
44
45 pub fn with_writes_allowed(mut self, writes_allowed: bool) -> Self {
47 self.writes_allowed = writes_allowed;
48 self
49 }
50}
51
52#[derive(Debug, Clone, Default)]
54pub struct CapabilityCatalog {
55 descriptors: HashMap<CapabilityName, CapabilityDescriptor>,
56}
57
58impl CapabilityCatalog {
59 pub fn new() -> Self {
61 Self::default()
62 }
63
64 pub fn from_descriptors(
66 descriptors: impl IntoIterator<Item = CapabilityDescriptor>,
67 ) -> CapabilityResult<Self> {
68 let mut catalog = Self::new();
69 for descriptor in descriptors {
70 catalog.register_descriptor(descriptor)?;
71 }
72 Ok(catalog)
73 }
74
75 pub fn register_descriptor(
77 &mut self,
78 descriptor: CapabilityDescriptor,
79 ) -> CapabilityResult<()> {
80 if self.descriptors.contains_key(&descriptor.name) {
81 return Err(CapabilityError::DescriptorAlreadyRegistered(
82 descriptor.name.clone(),
83 ));
84 }
85 self.descriptors.insert(descriptor.name.clone(), descriptor);
86 Ok(())
87 }
88
89 pub fn descriptor(&self, capability: &CapabilityName) -> Option<&CapabilityDescriptor> {
91 self.descriptors.get(capability)
92 }
93
94 pub fn descriptors(&self) -> Vec<&CapabilityDescriptor> {
96 let mut descriptors = self.descriptors.values().collect::<Vec<_>>();
97 descriptors.sort_by(|left, right| left.name.as_str().cmp(right.name.as_str()));
98 descriptors
99 }
100
101 pub fn resolve_local(
103 &self,
104 request: &CapabilityRequest,
105 ) -> CapabilityResult<&CapabilityDescriptor> {
106 let descriptor = self
107 .descriptor(&request.capability)
108 .ok_or_else(|| CapabilityError::CapabilityNotDeclared(request.capability.clone()))?;
109 crate::policy::enforce_request_requirements(request, descriptor)?;
110 Ok(descriptor)
111 }
112
113 pub fn authorize_local(
115 &self,
116 request: &CapabilityRequest,
117 context: CapabilityEnforcementContext<'_>,
118 ) -> CapabilityResult<()> {
119 let descriptor = self.resolve_local(request)?;
120 enforce_requirements(
121 context.identity,
122 context.service_id,
123 request,
124 descriptor,
125 &context.identity.core_id,
126 context.leadership,
127 context.writes_allowed,
128 context.now_ms,
129 )
130 }
131}