cedar_policy_core/entities/json/
schema.rs

1/*
2 * Copyright Cedar Contributors
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      https://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17use super::SchemaType;
18use crate::ast::{Entity, EntityType, EntityUID};
19use crate::entities::{Name, UnreservedId};
20use smol_str::SmolStr;
21use std::collections::HashSet;
22use std::sync::Arc;
23
24/// Trait for `Schema`s that can inform the parsing of Entity JSON data
25pub trait Schema {
26    /// Type returned by `entity_type()`. Must implement the `EntityTypeDescription` trait
27    type EntityTypeDescription: EntityTypeDescription;
28
29    /// Type returned by `action_entities()`
30    type ActionEntityIterator: IntoIterator<Item = Arc<Entity>>;
31
32    /// Get an `EntityTypeDescription` for the given entity type, or `None` if that
33    /// entity type is not declared in the schema (in which case entities of that
34    /// type should not appear in the JSON data).
35    fn entity_type(&self, entity_type: &EntityType) -> Option<Self::EntityTypeDescription>;
36
37    /// Get the entity information for the given action, or `None` if that
38    /// action is not declared in the schema (in which case this action should
39    /// not appear in the JSON data).
40    fn action(&self, action: &EntityUID) -> Option<Arc<Entity>>;
41
42    /// Get the names of all entity types declared in the schema that have the
43    /// given basename (in the sense of `Name::basename()`).
44    fn entity_types_with_basename<'a>(
45        &'a self,
46        basename: &'a UnreservedId,
47    ) -> Box<dyn Iterator<Item = EntityType> + 'a>;
48
49    /// Get all the actions declared in the schema
50    fn action_entities(&self) -> Self::ActionEntityIterator;
51}
52
53/// Simple type that implements `Schema` by expecting no entities to exist at all
54#[derive(Debug, Clone)]
55pub struct NoEntitiesSchema;
56impl Schema for NoEntitiesSchema {
57    type EntityTypeDescription = NullEntityTypeDescription;
58    type ActionEntityIterator = std::iter::Empty<Arc<Entity>>;
59    fn entity_type(&self, _entity_type: &EntityType) -> Option<NullEntityTypeDescription> {
60        None
61    }
62    fn action(&self, _action: &EntityUID) -> Option<Arc<Entity>> {
63        None
64    }
65    fn entity_types_with_basename<'a>(
66        &'a self,
67        _basename: &'a UnreservedId,
68    ) -> Box<dyn Iterator<Item = EntityType> + 'a> {
69        Box::new(std::iter::empty())
70    }
71    fn action_entities(&self) -> std::iter::Empty<Arc<Entity>> {
72        std::iter::empty()
73    }
74}
75
76/// Simple type that implements `Schema` by allowing entities of all types to
77/// exist, and allowing all actions to exist, but expecting no attributes, tags,
78/// or parents on any entity (action or otherwise).
79///
80/// This type returns an empty iterator for `action_entities()`, which is kind
81/// of inconsistent with its behavior on `action()`. But it works out -- the
82/// result is that, in `EntityJsonParser`, all actions encountered in JSON data
83/// are allowed to exist without error, but no additional actions from the
84/// schema are added.
85#[derive(Debug, Clone)]
86pub struct AllEntitiesNoAttrsSchema;
87impl Schema for AllEntitiesNoAttrsSchema {
88    type EntityTypeDescription = NullEntityTypeDescription;
89    type ActionEntityIterator = std::iter::Empty<Arc<Entity>>;
90    fn entity_type(&self, entity_type: &EntityType) -> Option<NullEntityTypeDescription> {
91        Some(NullEntityTypeDescription {
92            ty: entity_type.clone(),
93        })
94    }
95    fn action(&self, action: &EntityUID) -> Option<Arc<Entity>> {
96        Some(Arc::new(Entity::new_with_attr_partial_value(
97            action.clone(),
98            [],
99            HashSet::new(),
100            [],
101        )))
102    }
103    fn entity_types_with_basename<'a>(
104        &'a self,
105        basename: &'a UnreservedId,
106    ) -> Box<dyn Iterator<Item = EntityType> + 'a> {
107        Box::new(std::iter::once(EntityType::from(Name::unqualified_name(
108            basename.clone(),
109        ))))
110    }
111    fn action_entities(&self) -> std::iter::Empty<Arc<Entity>> {
112        std::iter::empty()
113    }
114}
115
116/// Trait for a schema's description of an individual entity type
117pub trait EntityTypeDescription {
118    /// Get the `EntityType` this `EntityTypeDescription` is describing
119    fn entity_type(&self) -> EntityType;
120
121    /// Do entities of this type have the given attribute, and if so, what type?
122    ///
123    /// Returning `None` indicates that attribute should not exist.
124    fn attr_type(&self, attr: &str) -> Option<SchemaType>;
125
126    /// If this entity has tags, what type should the tags be?
127    ///
128    /// Returning `None` indicates that no tags should exist for this entity type.
129    fn tag_type(&self) -> Option<SchemaType>;
130
131    /// Get the names of all the required attributes for this entity type.
132    fn required_attrs<'s>(&'s self) -> Box<dyn Iterator<Item = SmolStr> + 's>;
133
134    /// Get the entity types which are allowed to be parents of this entity type.
135    fn allowed_parent_types(&self) -> Arc<HashSet<EntityType>>;
136
137    /// May entities with this type have attributes other than those specified
138    /// in the schema
139    fn open_attributes(&self) -> bool;
140}
141
142/// Simple type that implements `EntityTypeDescription` by expecting no
143/// attributes, tags, or parents to exist
144#[derive(Debug, Clone)]
145pub struct NullEntityTypeDescription {
146    /// null description for this entity typename
147    ty: EntityType,
148}
149impl EntityTypeDescription for NullEntityTypeDescription {
150    fn entity_type(&self) -> EntityType {
151        self.ty.clone()
152    }
153    fn attr_type(&self, _attr: &str) -> Option<SchemaType> {
154        None
155    }
156    fn tag_type(&self) -> Option<SchemaType> {
157        None
158    }
159    fn required_attrs(&self) -> Box<dyn Iterator<Item = SmolStr>> {
160        Box::new(std::iter::empty())
161    }
162    fn allowed_parent_types(&self) -> Arc<HashSet<EntityType>> {
163        Arc::new(HashSet::new())
164    }
165    fn open_attributes(&self) -> bool {
166        false
167    }
168}
169impl NullEntityTypeDescription {
170    /// Create a new [`NullEntityTypeDescription`] for the given entity typename
171    pub fn new(ty: EntityType) -> Self {
172        Self { ty }
173    }
174}