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}