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::{Eid, Entity, EntityType, EntityUID};
19use crate::entities::{Name, UnreservedId};
20use nonempty::NonEmpty;
21use smol_str::SmolStr;
22use std::collections::HashSet;
23use std::sync::Arc;
24
25/// Trait for `Schema`s that can inform the parsing of Entity JSON data
26pub trait Schema {
27    /// Type returned by `entity_type()`. Must implement the `EntityTypeDescription` trait
28    type EntityTypeDescription: EntityTypeDescription;
29
30    /// Type returned by `action_entities()`
31    type ActionEntityIterator: IntoIterator<Item = Arc<Entity>>;
32
33    /// Get an `EntityTypeDescription` for the given entity type, or `None` if that
34    /// entity type is not declared in the schema (in which case entities of that
35    /// type should not appear in the JSON data).
36    fn entity_type(&self, entity_type: &EntityType) -> Option<Self::EntityTypeDescription>;
37
38    /// Get the entity information for the given action, or `None` if that
39    /// action is not declared in the schema (in which case this action should
40    /// not appear in the JSON data).
41    fn action(&self, action: &EntityUID) -> Option<Arc<Entity>>;
42
43    /// Get the names of all entity types declared in the schema that have the
44    /// given basename (in the sense of `Name::basename()`).
45    fn entity_types_with_basename<'a>(
46        &'a self,
47        basename: &'a UnreservedId,
48    ) -> Box<dyn Iterator<Item = EntityType> + 'a>;
49
50    /// Get all the actions declared in the schema
51    fn action_entities(&self) -> Self::ActionEntityIterator;
52}
53
54/// Simple type that implements `Schema` by expecting no entities to exist at all
55#[derive(Debug, Clone)]
56pub struct NoEntitiesSchema;
57impl Schema for NoEntitiesSchema {
58    type EntityTypeDescription = NullEntityTypeDescription;
59    type ActionEntityIterator = std::iter::Empty<Arc<Entity>>;
60    fn entity_type(&self, _entity_type: &EntityType) -> Option<NullEntityTypeDescription> {
61        None
62    }
63    fn action(&self, _action: &EntityUID) -> Option<Arc<Entity>> {
64        None
65    }
66    fn entity_types_with_basename<'a>(
67        &'a self,
68        _basename: &'a UnreservedId,
69    ) -> Box<dyn Iterator<Item = EntityType> + 'a> {
70        Box::new(std::iter::empty())
71    }
72    fn action_entities(&self) -> std::iter::Empty<Arc<Entity>> {
73        std::iter::empty()
74    }
75}
76
77/// Simple type that implements `Schema` by allowing entities of all types to
78/// exist, and allowing all actions to exist, but expecting no attributes, tags,
79/// or parents on any entity (action or otherwise).
80///
81/// This type returns an empty iterator for `action_entities()`, which is kind
82/// of inconsistent with its behavior on `action()`. But it works out -- the
83/// result is that, in `EntityJsonParser`, all actions encountered in JSON data
84/// are allowed to exist without error, but no additional actions from the
85/// schema are added.
86#[derive(Debug, Clone)]
87pub struct AllEntitiesNoAttrsSchema;
88impl Schema for AllEntitiesNoAttrsSchema {
89    type EntityTypeDescription = NullEntityTypeDescription;
90    type ActionEntityIterator = std::iter::Empty<Arc<Entity>>;
91    fn entity_type(&self, entity_type: &EntityType) -> Option<NullEntityTypeDescription> {
92        Some(NullEntityTypeDescription {
93            ty: entity_type.clone(),
94        })
95    }
96    fn action(&self, action: &EntityUID) -> Option<Arc<Entity>> {
97        Some(Arc::new(Entity::new_with_attr_partial_value(
98            action.clone(),
99            [],
100            HashSet::new(),
101            HashSet::new(),
102            [],
103        )))
104    }
105    fn entity_types_with_basename<'a>(
106        &'a self,
107        basename: &'a UnreservedId,
108    ) -> Box<dyn Iterator<Item = EntityType> + 'a> {
109        Box::new(std::iter::once(EntityType::from(Name::unqualified_name(
110            basename.clone(),
111        ))))
112    }
113    fn action_entities(&self) -> std::iter::Empty<Arc<Entity>> {
114        std::iter::empty()
115    }
116}
117
118/// Trait for a schema's description of an individual entity type
119pub trait EntityTypeDescription {
120    /// Get the `EntityType` this `EntityTypeDescription` is describing
121    fn entity_type(&self) -> EntityType;
122
123    /// Do entities of this type have the given attribute, and if so, what type?
124    ///
125    /// Returning `None` indicates that attribute should not exist.
126    fn attr_type(&self, attr: &str) -> Option<SchemaType>;
127
128    /// If this entity has tags, what type should the tags be?
129    ///
130    /// Returning `None` indicates that no tags should exist for this entity type.
131    fn tag_type(&self) -> Option<SchemaType>;
132
133    /// Get the names of all the required attributes for this entity type.
134    fn required_attrs<'s>(&'s self) -> Box<dyn Iterator<Item = SmolStr> + 's>;
135
136    /// Get the entity types which are allowed to be parents of this entity type.
137    fn allowed_parent_types(&self) -> Arc<HashSet<EntityType>>;
138
139    /// May entities with this type have attributes other than those specified
140    /// in the schema
141    fn open_attributes(&self) -> bool;
142
143    /// Return valid EID choices if the entity type is enumerated otherwise
144    /// return `None`
145    fn enum_entity_eids(&self) -> Option<NonEmpty<Eid>>;
146}
147
148/// Simple type that implements `EntityTypeDescription` by expecting no
149/// attributes, tags, or parents to exist
150#[derive(Debug, Clone)]
151pub struct NullEntityTypeDescription {
152    /// null description for this entity typename
153    ty: EntityType,
154}
155impl EntityTypeDescription for NullEntityTypeDescription {
156    fn entity_type(&self) -> EntityType {
157        self.ty.clone()
158    }
159    fn attr_type(&self, _attr: &str) -> Option<SchemaType> {
160        None
161    }
162    fn tag_type(&self) -> Option<SchemaType> {
163        None
164    }
165    fn required_attrs(&self) -> Box<dyn Iterator<Item = SmolStr>> {
166        Box::new(std::iter::empty())
167    }
168    fn allowed_parent_types(&self) -> Arc<HashSet<EntityType>> {
169        Arc::new(HashSet::new())
170    }
171    fn open_attributes(&self) -> bool {
172        false
173    }
174    fn enum_entity_eids(&self) -> Option<NonEmpty<Eid>> {
175        None
176    }
177}
178impl NullEntityTypeDescription {
179    /// Create a new [`NullEntityTypeDescription`] for the given entity typename
180    pub fn new(ty: EntityType) -> Self {
181        Self { ty }
182    }
183}