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
//! This module contains the definition of `ValidatorActionId` and the types it relies on
use cedar_policy_core::{
ast::{EntityType, EntityUID, PartialValueSerializedAsExpr},
transitive_closure::TCNode,
};
use serde::Serialize;
use smol_str::SmolStr;
use std::collections::{HashMap, HashSet};
use crate::types::{Attributes, Type};
/// Contains information about actions used by the validator. The contents of
/// the struct are the same as the schema entity type structure, but the
/// `member_of` relation is reversed to instead be `descendants`.
#[derive(Clone, Debug, Serialize)]
pub struct ValidatorActionId {
/// The name of the action.
pub(crate) name: EntityUID,
/// The principals and resources that the action can be applied to.
#[serde(rename = "appliesTo")]
pub(crate) applies_to: ValidatorApplySpec,
/// The set of actions that can be members of this action. When this
/// structure is initially constructed, the field will contain direct
/// children, but it will be updated to contain the closure of all
/// descendants before it is used in any validation.
pub(crate) descendants: HashSet<EntityUID>,
/// The type of the context record associated with this action.
pub(crate) context: Type,
/// The attribute types for this action, used for typechecking.
pub(crate) attribute_types: Attributes,
/// The actual attribute value for this action, used to construct an
/// `Entity` for this action. Could also be used for more precise
/// typechecking by partial evaluation.
///
/// Attributes are serialized as `RestrictedExpr`s, so that roundtripping
/// works seamlessly.
pub(crate) attributes: HashMap<SmolStr, PartialValueSerializedAsExpr>,
}
impl ValidatorActionId {
/// The `Type` that this action requires for its context.
///
/// This always returns a closed record type.
pub fn context_type(&self) -> Type {
self.context.clone()
}
}
impl TCNode<EntityUID> for ValidatorActionId {
fn get_key(&self) -> EntityUID {
self.name.clone()
}
fn add_edge_to(&mut self, k: EntityUID) {
self.descendants.insert(k);
}
fn out_edges(&self) -> Box<dyn Iterator<Item = &EntityUID> + '_> {
Box::new(self.descendants.iter())
}
fn has_edge_to(&self, e: &EntityUID) -> bool {
self.descendants.contains(e)
}
}
/// The principals and resources that an action can be applied to.
#[derive(Clone, Debug, Serialize)]
pub(crate) struct ValidatorApplySpec {
/// The principal entity types the action can be applied to. This set may
/// be a singleton set containing the unspecified entity type when the
/// `principalTypes` list is omitted in the schema. A non-singleton set
/// shouldn't contain the unspecified entity type, but (policy) validation
/// will give the same success/failure result as when it is the only element
/// of the set, perhaps with extra type errors.
#[serde(rename = "principalApplySpec")]
principal_apply_spec: HashSet<EntityType>,
/// The resource entity types the action can be applied to. See comments on
/// `principal_apply_spec` about the unspecified entity type.
#[serde(rename = "resourceApplySpec")]
resource_apply_spec: HashSet<EntityType>,
}
impl ValidatorApplySpec {
/// Create an apply spec for an action that can only be applied to some
/// specific entities.
pub fn new(
principal_apply_spec: HashSet<EntityType>,
resource_apply_spec: HashSet<EntityType>,
) -> Self {
Self {
principal_apply_spec,
resource_apply_spec,
}
}
/// Is the given principal type applicable for this spec?
pub fn is_applicable_principal_type(&self, ty: &EntityType) -> bool {
self.principal_apply_spec.contains(ty)
}
/// Get the applicable principal types for this spec.
pub fn applicable_principal_types(&self) -> impl Iterator<Item = &EntityType> {
self.principal_apply_spec.iter()
}
/// Is the given resource type applicable for this spec?
pub fn is_applicable_resource_type(&self, ty: &EntityType) -> bool {
self.resource_apply_spec.contains(ty)
}
/// Get the applicable resource types for this spec.
pub fn applicable_resource_types(&self) -> impl Iterator<Item = &EntityType> {
self.resource_apply_spec.iter()
}
}