1use std::collections::HashMap;
2
3use zanzibar::Schema;
4
5use crate::{Namespace, Relation, default_schema};
6
7use super::*;
8
9#[derive(Debug, Clone)]
10pub struct DefaultAuthModelPackage {
11 manifest: AuthModelManifest,
12 schema: Schema,
13 capability_bindings: HashMap<Capability, CapabilityBinding>,
14}
15
16impl Default for DefaultAuthModelPackage {
17 fn default() -> Self {
18 Self::new()
19 }
20}
21
22impl DefaultAuthModelPackage {
23 pub fn new() -> Self {
24 Self {
25 manifest: default_manifest(),
26 schema: default_schema(),
27 capability_bindings: default_capability_bindings(),
28 }
29 }
30}
31
32impl AuthModelPackage for DefaultAuthModelPackage {
33 fn manifest(&self) -> &AuthModelManifest {
34 &self.manifest
35 }
36
37 fn schema(&self) -> &Schema {
38 &self.schema
39 }
40
41 fn capability_bindings(&self) -> &HashMap<Capability, CapabilityBinding> {
42 &self.capability_bindings
43 }
44}
45
46#[derive(Debug, Clone)]
47pub struct ConfiguredAuthModelPackage {
48 manifest: AuthModelManifest,
49 schema: Schema,
50 capability_bindings: HashMap<Capability, CapabilityBinding>,
51}
52
53impl ConfiguredAuthModelPackage {
54 pub fn new(name: impl Into<String>) -> Self {
57 let mut manifest = default_manifest();
58 manifest.name = name.into();
59 Self {
60 manifest,
61 schema: default_schema(),
62 capability_bindings: default_capability_bindings(),
63 }
64 }
65}
66
67impl AuthModelPackage for ConfiguredAuthModelPackage {
68 fn manifest(&self) -> &AuthModelManifest {
69 &self.manifest
70 }
71
72 fn schema(&self) -> &Schema {
73 &self.schema
74 }
75
76 fn capability_bindings(&self) -> &HashMap<Capability, CapabilityBinding> {
77 &self.capability_bindings
78 }
79}
80
81pub fn default_auth_model_package() -> DefaultAuthModelPackage {
82 DefaultAuthModelPackage::default()
83}
84
85pub fn configured_auth_model_package(name: impl Into<String>) -> ConfiguredAuthModelPackage {
86 ConfiguredAuthModelPackage::new(name)
87}
88
89pub fn configured_auth_model_package_selection(
94 name: impl Into<String>,
95) -> AuthModelPackageSelection {
96 AuthModelPackageSelection::new(configured_auth_model_package(name))
97}
98
99pub fn deployment_auth_model_package(name: impl Into<String>) -> ConfiguredAuthModelPackage {
102 ConfiguredAuthModelPackage::new(name)
103}
104
105pub fn deployment_auth_model_package_selection(
108 name: impl Into<String>,
109) -> AuthModelPackageSelection {
110 configured_auth_model_package_selection(name)
111}
112
113#[cfg(test)]
114mod tests {
115 use super::*;
116 use crate::{AuthModelPackage, Capability};
117
118 #[test]
119 fn configured_package_selection_preserves_identity_and_bindings() {
120 let package = configured_auth_model_package_selection("coil-extended-auth");
121
122 assert_eq!(package.manifest().name, "coil-extended-auth");
123 assert_eq!(
124 package
125 .package()
126 .binding_for(Capability::CmsPageRead)
127 .unwrap(),
128 DefaultAuthModelPackage::default()
129 .binding_for(Capability::CmsPageRead)
130 .unwrap()
131 );
132 }
133
134 #[test]
135 fn deployment_package_preserves_identity_while_reusing_default_bindings() {
136 let package = deployment_auth_model_package("coil-extended-auth");
137
138 assert_eq!(package.manifest().name, "coil-extended-auth");
139 assert_eq!(
140 package.binding_for(Capability::CmsPageRead).unwrap(),
141 DefaultAuthModelPackage::default()
142 .binding_for(Capability::CmsPageRead)
143 .unwrap()
144 );
145 }
146}
147
148pub fn default_manifest() -> AuthModelManifest {
149 AuthModelManifest {
150 name: "coil-default-auth".to_string(),
151 version: PackageVersion::new(1, 0, 0),
152 mode: PackageMode::Replace,
153 storage_schema_version: 1,
154 model_version: 1,
155 capability_binding_version: 1,
156 imports: Vec::new(),
157 }
158}
159
160pub fn default_capability_bindings() -> HashMap<Capability, CapabilityBinding> {
161 HashMap::from([
162 binding(
163 Capability::SystemModuleManage,
164 vec![Namespace::Tenant],
165 Relation::Manage,
166 ),
167 binding(
168 Capability::SystemConfigRead,
169 vec![Namespace::Tenant],
170 Relation::View,
171 ),
172 binding(
173 Capability::SystemConfigWrite,
174 vec![Namespace::Tenant],
175 Relation::Manage,
176 ),
177 binding(
178 Capability::AdminShellAccess,
179 vec![Namespace::AdminModule],
180 Relation::View,
181 ),
182 binding(
183 Capability::AdminAuditRead,
184 vec![Namespace::AdminModule],
185 Relation::Read,
186 ),
187 binding(
188 Capability::CmsPageRead,
189 vec![Namespace::Page],
190 Relation::View,
191 ),
192 binding(
193 Capability::CmsPagePublish,
194 vec![Namespace::Page],
195 Relation::Publish,
196 ),
197 binding(
198 Capability::CmsPageEdit,
199 vec![Namespace::Page],
200 Relation::Edit,
201 ),
202 binding(
203 Capability::CmsNavigationEdit,
204 vec![Namespace::Navigation],
205 Relation::Edit,
206 ),
207 binding(
208 Capability::CatalogProductRead,
209 vec![Namespace::Product],
210 Relation::View,
211 ),
212 binding(
213 Capability::CatalogProductEdit,
214 vec![Namespace::Product],
215 Relation::Edit,
216 ),
217 binding(
218 Capability::CatalogCollectionEdit,
219 vec![Namespace::Collection],
220 Relation::Edit,
221 ),
222 binding(
223 Capability::CheckoutSessionCreate,
224 vec![Namespace::Storefront],
225 Relation::Checkout,
226 ),
227 binding(
228 Capability::OrderRead,
229 vec![Namespace::Order],
230 Relation::View,
231 ),
232 binding(
233 Capability::OrderRefundIssue,
234 vec![Namespace::Order],
235 Relation::Refund,
236 ),
237 binding(
238 Capability::MembershipSubscriptionManage,
239 vec![Namespace::Subscription],
240 Relation::Manage,
241 ),
242 binding(
243 Capability::MembershipTierEdit,
244 vec![Namespace::MembershipTier],
245 Relation::Edit,
246 ),
247 binding(
248 Capability::EventsEventPublish,
249 vec![Namespace::Event],
250 Relation::Publish,
251 ),
252 binding(
253 Capability::EventsSlotManage,
254 vec![Namespace::EventSlot],
255 Relation::Manage,
256 ),
257 binding(
258 Capability::EventsBookingManage,
259 vec![Namespace::Booking],
260 Relation::Manage,
261 ),
262 binding(
263 Capability::EventsBookingCreate,
264 vec![Namespace::EventSlot],
265 Relation::Book,
266 ),
267 binding(
268 Capability::EventsBookingCheckIn,
269 vec![Namespace::Booking],
270 Relation::CheckIn,
271 ),
272 binding(
273 Capability::AssetRead,
274 vec![Namespace::Asset],
275 Relation::Read,
276 ),
277 binding(
278 Capability::AssetReadPublic,
279 vec![Namespace::Asset],
280 Relation::ReadPublic,
281 ),
282 binding(
283 Capability::AssetPublish,
284 vec![Namespace::Asset],
285 Relation::Publish,
286 ),
287 binding(
288 Capability::AssetReplace,
289 vec![Namespace::Asset],
290 Relation::Replace,
291 ),
292 binding(
293 Capability::AssetManageStorage,
294 vec![Namespace::Asset],
295 Relation::ManageStorage,
296 ),
297 binding(
298 Capability::SeoMetadataEdit,
299 vec![Namespace::Page, Namespace::Product, Namespace::Event],
300 Relation::Edit,
301 ),
302 binding(
303 Capability::I18nTranslationEdit,
304 vec![
305 Namespace::Page,
306 Namespace::Navigation,
307 Namespace::Product,
308 Namespace::MembershipTier,
309 Namespace::Event,
310 ],
311 Relation::Edit,
312 ),
313 ])
314}
315
316fn binding(
317 capability: Capability,
318 resource_namespaces: Vec<Namespace>,
319 relation: Relation,
320) -> (Capability, CapabilityBinding) {
321 (
322 capability,
323 CapabilityBinding {
324 capability,
325 resource_namespaces,
326 relation,
327 },
328 )
329}