Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions cedar-policy-cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name = "cedar-policy-cli"
edition = "2021"
rust-version = "1.76.0" # minimum supported Rust version is currently 1.76.0 because `cedar-policy-core` requirement. Check with `cargo install cargo-msrv && cargo msrv --min 1.75.0`

version = "3.3.0"
version = "3.4.0"
license = "Apache-2.0"
categories = ["compilers", "config"]
description = "CLI interface for the Cedar Policy language."
Expand All @@ -12,8 +12,8 @@ homepage = "https://cedarpolicy.com"
repository = "https://github.com/cedar-policy/cedar"

[dependencies]
cedar-policy = { version = "=3.3.0", path = "../cedar-policy" }
cedar-policy-formatter = { version = "=3.3.0", path = "../cedar-policy-formatter" }
cedar-policy = { version = "=3.4.0", path = "../cedar-policy" }
cedar-policy-formatter = { version = "=3.4.0", path = "../cedar-policy-formatter" }
clap = { version = "4", features = ["derive", "env"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
Expand Down
2 changes: 1 addition & 1 deletion cedar-policy-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ edition = "2021"
rust-version = "1.76.0" # minimum supported Rust version is currently 1.76.0 because of use of `Arc::unwrap_or_clone()`. Check with `cargo install cargo-msrv && cargo msrv --min 1.75.0`
build = "build.rs"

version = "3.3.0"
version = "3.4.0"
license = "Apache-2.0"
categories = ["compilers", "config"]
description = "Core implemenation of the Cedar Policy language."
Expand Down
16 changes: 16 additions & 0 deletions cedar-policy-core/src/ast/entity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -287,8 +287,17 @@ pub struct Entity {
ancestors: HashSet<EntityUID>,
}

impl std::hash::Hash for Entity {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.uid.hash(state);
}
}

impl Entity {
/// Create a new `Entity` with this UID, attributes, and ancestors
///
/// # Errors
/// - Will error if any of the [`RestrictedExpr]`s in `attrs` error when evaluated
pub fn new(
uid: EntityUID,
attrs: HashMap<SmolStr, RestrictedExpr>,
Expand Down Expand Up @@ -316,6 +325,13 @@ impl Entity {
})
}

/// Create a new `Entity` with this UID, ancestors, and an empty set of attributes
///
/// Since there are no attributes, this method does not error, and returns `Self` instead of `Result<Self>`
pub fn new_empty_attrs(uid: EntityUID, ancestors: HashSet<EntityUID>) -> Self {
Self::new_with_attr_partial_value(uid, HashMap::new(), ancestors)
}

/// Create a new `Entity` with this UID, attributes, and ancestors.
///
/// Unlike in `Entity::new()`, in this constructor, attributes are expressed
Expand Down
9 changes: 8 additions & 1 deletion cedar-policy-core/src/entities.rs
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,13 @@ impl Entities {
///
/// If you pass `TCComputation::AssumeAlreadyComputed`, then the caller is
/// responsible for ensuring that TC and DAG hold before calling this method.
///
/// # Errors
/// - [`EntitiesError::Duplicate`] if there are any duplicate entities in `entities`
/// - [`EntitiesError::TransitiveClosureError`] if `tc_computation ==
/// TCComputation::EnforceAlreadyComputed` and the entities are not transitivly closed
/// - [`EntitiesError::InvalidEntity`] if `schema` is not none and any entities do not conform
/// to the schema
pub fn from_entities(
entities: impl IntoIterator<Item = Entity>,
schema: Option<&impl Schema>,
Expand Down Expand Up @@ -809,7 +816,7 @@ mod json_parsing_tests {
parser.from_json_value(json).expect("JSON is correct")
}

/// Ensure the initial conditions of the entiites still hold
/// Ensure the initial conditions of the entities still hold
fn simple_entities_still_sane(e: &Entities) {
let bob = r#"Test::"bob""#.parse().unwrap();
let alice = e.entity(&r#"Test::"alice""#.parse().unwrap()).unwrap();
Expand Down
80 changes: 64 additions & 16 deletions cedar-policy-core/src/entities/conformance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
* limitations under the License.
*/

use std::collections::BTreeMap;

use super::{
schematype_of_restricted_expr, EntityTypeDescription, GetSchemaTypeError,
HeterogeneousSetError, Schema, SchemaType, TypeMismatchError,
Expand Down Expand Up @@ -291,6 +293,60 @@ pub fn typecheck_value_against_schematype(
}
}

/// Check whether the given `RestrictedExpr` is a valid instance of `SchemaType`
pub fn does_restricted_expr_implement_schematype(
expr: BorrowedRestrictedExpr<'_>,
expected_ty: &SchemaType,
) -> bool {
use SchemaType::*;

match expected_ty {
Bool => expr.as_bool().is_some(),
Long => expr.as_long().is_some(),
String => expr.as_string().is_some(),
EmptySet => expr.as_set_elements().is_some_and(|e| e.count() == 0),
Set { .. } if expr.as_set_elements().is_some_and(|e| e.count() == 0) => true,
Set { element_ty: elty } => match expr.as_set_elements() {
Some(mut els) => els.all(|e| does_restricted_expr_implement_schematype(e, elty)),
None => false,
},
Record { attrs, open_attrs } => match expr.as_record_pairs() {
Some(pairs) => {
let pairs_map: BTreeMap<&SmolStr, BorrowedRestrictedExpr<'_>> = pairs.collect();
let all_req_schema_attrs_in_record = attrs.iter().all(|(k, v)| {
!v.required
|| match pairs_map.get(k) {
Some(inner_e) => {
does_restricted_expr_implement_schematype(*inner_e, &v.attr_type)
}
None => false,
}
});
let all_rec_attrs_match_schema =
pairs_map.iter().all(|(k, inner_e)| match attrs.get(*k) {
Some(sch_ty) => {
does_restricted_expr_implement_schematype(*inner_e, &sch_ty.attr_type)
}
None => *open_attrs,
});
all_rec_attrs_match_schema && all_req_schema_attrs_in_record
}
None => false,
},
Extension { name } => match expr.as_extn_fn_call() {
Some((actual_name, _)) => match name.id.as_ref() {
"ipaddr" => actual_name.id.as_ref() == "ip",
_ => name == actual_name,
},
None => false,
},
Entity { ty } => match expr.as_euid() {
Some(actual_euid) => actual_euid.entity_type() == ty,
None => false,
},
}
}

/// Check whether the given `RestrictedExpr` typechecks with the given `SchemaType`.
/// If the typecheck passes, return `Ok(())`.
/// If the typecheck fails, return an appropriate `Err`.
Expand All @@ -299,23 +355,15 @@ pub fn typecheck_restricted_expr_against_schematype(
expected_ty: &SchemaType,
extensions: Extensions<'_>,
) -> Result<(), TypecheckError> {
// TODO(#440): instead of computing the `SchemaType` of `expr` and then
// checking whether the schematypes are "consistent", wouldn't it be less
// confusing, more efficient, and maybe even more precise to just typecheck
// directly?
if does_restricted_expr_implement_schematype(expr, expected_ty) {
return Ok(());
}
match schematype_of_restricted_expr(expr, extensions) {
Ok(actual_ty) => {
if actual_ty.is_consistent_with(expected_ty) {
// typecheck passes
Ok(())
} else {
Err(TypecheckError::TypeMismatch(TypeMismatchError {
expected: Box::new(expected_ty.clone()),
actual_ty: Some(Box::new(actual_ty)),
actual_val: Either::Right(Box::new(expr.to_owned())),
}))
}
}
Ok(actual_ty) => Err(TypecheckError::TypeMismatch(TypeMismatchError {
expected: Box::new(expected_ty.clone()),
actual_ty: Some(Box::new(actual_ty)),
actual_val: Either::Right(Box::new(expr.to_owned())),
})),
Err(GetSchemaTypeError::UnknownInsufficientTypeInfo { .. }) => {
// in this case we just don't have the information to know whether
// the attribute value (an unknown) matches the expected type.
Expand Down
16 changes: 6 additions & 10 deletions cedar-policy-core/src/entities/json/schema_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,9 @@ pub enum SchemaType {
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct AttributeType {
/// Type of the attribute
attr_type: SchemaType,
pub(crate) attr_type: SchemaType,
/// Is the attribute required
required: bool,
pub(crate) required: bool,
}

impl SchemaType {
Expand Down Expand Up @@ -313,11 +313,8 @@ pub struct HeterogeneousSetError {
/// required or optional.
/// This function, when given a record that has keys A, B, and C, will return a
/// `SchemaType` where A, B, and C are all marked as optional attributes, but no
/// other attributes are possible.
/// That is, this assumes that all existing attributes are optional, but that no
/// other optional attributes are possible.
/// Compared to marking A, B, and C as required, this allows the returned
/// `SchemaType` to `is_consistent_with()` more types.
/// other attributes are possible. This maximized flexibility while avoiding
/// heterogeneous sets.
///
/// This function may return `GetSchemaTypeError`, but should never return
/// `NontrivialResidual`, because `RestrictedExpr`s can't contain nontrivial
Expand All @@ -341,9 +338,8 @@ pub fn schematype_of_restricted_expr(
BorrowedRestrictedExpr::new_unchecked(v), // assuming the invariant holds for the record as a whole, it will also hold for each attribute value
extensions,
)?;
// we can't know if the attribute is required or optional,
// but marking it optional is more flexible -- allows the
// attribute type to `is_consistent_with()` more types
// We can't know if the attribute is required or optional.
// Keep as optional to minimize heterogeneous sets.
Ok((k.clone(), AttributeType::optional(attr_type)))
}).collect::<Result<HashMap<_,_>, GetSchemaTypeError>>()?,
open_attrs: false,
Expand Down
4 changes: 2 additions & 2 deletions cedar-policy-formatter/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "cedar-policy-formatter"
version = "3.3.0"
version = "3.4.0"
edition = "2021"
rust-version = "1.76.0" # minimum supported Rust version is currently 1.76.0 because `cedar-policy-core` requirement. Check with `cargo install cargo-msrv && cargo msrv --min 1.75.0`
license = "Apache-2.0"
Expand All @@ -11,7 +11,7 @@ homepage = "https://cedarpolicy.com"
repository = "https://github.com/cedar-policy/cedar"

[dependencies]
cedar-policy-core = { version = "=3.3.0", path = "../cedar-policy-core" }
cedar-policy-core = { version = "=3.4.0", path = "../cedar-policy-core" }
pretty = "0.12.1"
logos = "0.14.0"
itertools = "0.12"
Expand Down
6 changes: 3 additions & 3 deletions cedar-policy-validator/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name = "cedar-policy-validator"
edition = "2021"
rust-version = "1.76.0" # minimum supported Rust version is currently 1.76.0 because `cedar-policy-core` requirement. Check with `cargo install cargo-msrv && cargo msrv --min 1.75.0`

version = "3.3.0"
version = "3.4.0"
license = "Apache-2.0"
categories = ["compilers", "config"]
description = "Validator for the Cedar Policy language."
Expand All @@ -12,7 +12,7 @@ homepage = "https://cedarpolicy.com"
repository = "https://github.com/cedar-policy/cedar"

[dependencies]
cedar-policy-core = { version = "=3.3.0", path = "../cedar-policy-core" }
cedar-policy-core = { version = "=3.4.0", path = "../cedar-policy-core" }
serde = { version = "1.0", features = ["derive"] }
serde_json = { version = "1.0", features = ["preserve_order"] }
serde_with = "3.0"
Expand Down Expand Up @@ -49,7 +49,7 @@ wasm = ["serde-wasm-bindgen", "tsify", "wasm-bindgen"]

[dev-dependencies]
cool_asserts = "2.0"
cedar-policy-core = { version = "=3.3.0", path = "../cedar-policy-core", features = [
cedar-policy-core = { version = "=3.4.0", path = "../cedar-policy-core", features = [
"test-util",
] }

Expand Down
6 changes: 3 additions & 3 deletions cedar-policy/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name = "cedar-policy"
edition = "2021"
rust-version = "1.76.0" # minimum supported Rust version is currently 1.76.0 because `cedar-policy-core` requirement. Check with `cargo install cargo-msrv && cargo msrv --min 1.75.0`

version = "3.3.0"
version = "3.4.0"
license = "Apache-2.0"
categories = ["compilers", "config"]
description = "Cedar is a language for defining permissions as policies, which describe who should have access to what."
Expand All @@ -12,8 +12,8 @@ homepage = "https://cedarpolicy.com"
repository = "https://github.com/cedar-policy/cedar"

[dependencies]
cedar-policy-core = { version = "=3.3.0", features = ["test-util"], path = "../cedar-policy-core" }
cedar-policy-validator = { version = "=3.3.0", path = "../cedar-policy-validator" }
cedar-policy-core = { version = "=3.4.0", features = ["test-util"], path = "../cedar-policy-core" }
cedar-policy-validator = { version = "=3.4.0", path = "../cedar-policy-validator" }
ref-cast = "1.0"
serde = { version = "1.0", features = ["derive", "rc"] }
serde_json = "1.0"
Expand Down
Loading