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