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}