cedar_policy_validator/schema/
action.rs

1//! This module contains the definition of `ValidatorActionId` and the types it relies on
2
3use cedar_policy_core::{
4    ast::{EntityType, EntityUID, PartialValueSerializedAsExpr},
5    transitive_closure::TCNode,
6};
7use serde::Serialize;
8use smol_str::SmolStr;
9use std::collections::{HashMap, HashSet};
10
11use crate::types::{Attributes, Type};
12
13/// Contains information about actions used by the validator.  The contents of
14/// the struct are the same as the schema entity type structure, but the
15/// `member_of` relation is reversed to instead be `descendants`.
16#[derive(Clone, Debug, Serialize)]
17pub struct ValidatorActionId {
18    /// The name of the action.
19    pub(crate) name: EntityUID,
20
21    /// The principals and resources that the action can be applied to.
22    #[serde(rename = "appliesTo")]
23    pub(crate) applies_to: ValidatorApplySpec,
24
25    /// The set of actions that can be members of this action. When this
26    /// structure is initially constructed, the field will contain direct
27    /// children, but it will be updated to contain the closure of all
28    /// descendants before it is used in any validation.
29    pub(crate) descendants: HashSet<EntityUID>,
30
31    /// The type of the context record associated with this action.
32    pub(crate) context: Type,
33
34    /// The attribute types for this action, used for typechecking.
35    pub(crate) attribute_types: Attributes,
36
37    /// The actual attribute value for this action, used to construct an
38    /// `Entity` for this action. Could also be used for more precise
39    /// typechecking by partial evaluation.
40    ///
41    /// Attributes are serialized as `RestrictedExpr`s, so that roundtripping
42    /// works seamlessly.
43    pub(crate) attributes: HashMap<SmolStr, PartialValueSerializedAsExpr>,
44}
45
46impl ValidatorActionId {
47    /// The `Type` that this action requires for its context.
48    ///
49    /// This always returns a closed record type.
50    pub fn context_type(&self) -> Type {
51        self.context.clone()
52    }
53}
54
55impl TCNode<EntityUID> for ValidatorActionId {
56    fn get_key(&self) -> EntityUID {
57        self.name.clone()
58    }
59
60    fn add_edge_to(&mut self, k: EntityUID) {
61        self.descendants.insert(k);
62    }
63
64    fn out_edges(&self) -> Box<dyn Iterator<Item = &EntityUID> + '_> {
65        Box::new(self.descendants.iter())
66    }
67
68    fn has_edge_to(&self, e: &EntityUID) -> bool {
69        self.descendants.contains(e)
70    }
71}
72
73/// The principals and resources that an action can be applied to.
74#[derive(Clone, Debug, Serialize)]
75pub(crate) struct ValidatorApplySpec {
76    /// The principal entity types the action can be applied to. This set may
77    /// be a singleton set containing the unspecified entity type when the
78    /// `principalTypes` list is omitted in the schema. A non-singleton set
79    /// shouldn't contain the unspecified entity type, but (policy) validation
80    /// will give the same success/failure result as when it is the only element
81    /// of the set, perhaps with extra type errors.
82    #[serde(rename = "principalApplySpec")]
83    principal_apply_spec: HashSet<EntityType>,
84
85    /// The resource entity types the action can be applied to. See comments on
86    /// `principal_apply_spec` about the unspecified entity type.
87    #[serde(rename = "resourceApplySpec")]
88    resource_apply_spec: HashSet<EntityType>,
89}
90
91impl ValidatorApplySpec {
92    /// Create an apply spec for an action that can only be applied to some
93    /// specific entities.
94    pub fn new(
95        principal_apply_spec: HashSet<EntityType>,
96        resource_apply_spec: HashSet<EntityType>,
97    ) -> Self {
98        Self {
99            principal_apply_spec,
100            resource_apply_spec,
101        }
102    }
103
104    /// Is the given principal type applicable for this spec?
105    pub fn is_applicable_principal_type(&self, ty: &EntityType) -> bool {
106        self.principal_apply_spec.contains(ty)
107    }
108
109    /// Get the applicable principal types for this spec.
110    pub fn applicable_principal_types(&self) -> impl Iterator<Item = &EntityType> {
111        self.principal_apply_spec.iter()
112    }
113
114    /// Is the given resource type applicable for this spec?
115    pub fn is_applicable_resource_type(&self, ty: &EntityType) -> bool {
116        self.resource_apply_spec.contains(ty)
117    }
118
119    /// Get the applicable resource types for this spec.
120    pub fn applicable_resource_types(&self) -> impl Iterator<Item = &EntityType> {
121        self.resource_apply_spec.iter()
122    }
123}