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