diff --git a/cedar-policy-cli/CHANGELOG.md b/cedar-policy-cli/CHANGELOG.md index 8057124c4..6c78cdaf1 100644 --- a/cedar-policy-cli/CHANGELOG.md +++ b/cedar-policy-cli/CHANGELOG.md @@ -1,5 +1,7 @@ # Changelog +## 3.1.4 + ## 3.1.3 - The `translate-schema` command now produces prettier output. diff --git a/cedar-policy-cli/Cargo.toml b/cedar-policy-cli/Cargo.toml index 88f03453b..456c4e0c0 100644 --- a/cedar-policy-cli/Cargo.toml +++ b/cedar-policy-cli/Cargo.toml @@ -2,7 +2,7 @@ name = "cedar-policy-cli" edition = "2021" -version = "3.1.3" +version = "3.1.4" license = "Apache-2.0" categories = ["compilers", "config"] description = "CLI interface for the Cedar Policy language." @@ -11,8 +11,8 @@ homepage = "https://cedarpolicy.com" repository = "https://github.com/cedar-policy/cedar" [dependencies] -cedar-policy = { version = "=3.1.3", path = "../cedar-policy" } -cedar-policy-formatter = { version = "=3.1.3", path = "../cedar-policy-formatter" } +cedar-policy = { version = "=3.1.4", path = "../cedar-policy" } +cedar-policy-formatter = { version = "=3.1.4", path = "../cedar-policy-formatter" } clap = { version = "4", features = ["derive", "env"] } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" diff --git a/cedar-policy-core/Cargo.toml b/cedar-policy-core/Cargo.toml index a3b40ffdc..df0c74631 100644 --- a/cedar-policy-core/Cargo.toml +++ b/cedar-policy-core/Cargo.toml @@ -3,7 +3,7 @@ name = "cedar-policy-core" edition = "2021" build = "build.rs" -version = "3.1.3" +version = "3.1.4" license = "Apache-2.0" categories = ["compilers", "config"] description = "Core implemenation of the Cedar Policy language." diff --git a/cedar-policy-formatter/Cargo.toml b/cedar-policy-formatter/Cargo.toml index 12b093970..13a93d75f 100644 --- a/cedar-policy-formatter/Cargo.toml +++ b/cedar-policy-formatter/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cedar-policy-formatter" -version = "3.1.3" +version = "3.1.4" edition = "2021" license = "Apache-2.0" categories = ["compilers", "config"] @@ -10,7 +10,7 @@ homepage = "https://cedarpolicy.com" repository = "https://github.com/cedar-policy/cedar" [dependencies] -cedar-policy-core = { version = "=3.1.3", path = "../cedar-policy-core" } +cedar-policy-core = { version = "=3.1.4", path = "../cedar-policy-core" } pretty = "0.12.1" logos = "0.14.0" itertools = "0.12" diff --git a/cedar-policy-formatter/src/pprint/fmt.rs b/cedar-policy-formatter/src/pprint/fmt.rs index 45e0fbe93..eeed13452 100644 --- a/cedar-policy-formatter/src/pprint/fmt.rs +++ b/cedar-policy-formatter/src/pprint/fmt.rs @@ -14,11 +14,14 @@ * limitations under the License. */ +use std::collections::BTreeMap; + use miette::{miette, Result, WrapErr}; -use cedar_policy_core::ast::{PolicySet, Template}; +use cedar_policy_core::ast::PolicySet; use cedar_policy_core::parser::parse_policyset; use cedar_policy_core::parser::{err::ParseErrors, text_to_cst::parse_policies}; +use smol_str::ToSmolStr; use crate::token::get_comment; @@ -40,17 +43,31 @@ fn tree_to_pretty(t: &T, context: &mut config::Context<'_>) -> Result Result<()> { - let formatted_ast = parse_policyset(ps).wrap_err("formatter produces invalid policies")?; + let formatted_ast = + parse_policyset(ps).wrap_err(format!("formatter produced an invalid policy set:\n{ps}"))?; let (formatted_policies, policies) = ( - formatted_ast.templates().collect::>(), - ast.templates().collect::>(), + formatted_ast + .policies() + .map(|p| (p.id().to_smolstr(), p)) + .collect::>(), + ast.policies() + .map(|p| (p.id().to_smolstr(), p)) + .collect::>(), ); if formatted_policies.len() != policies.len() { - return Err(miette!("missing formatted policies")); + return Err(miette!( + "formatter changed the number of policies from {} to {}", + policies.len(), + formatted_policies.len() + )); } - - for (f_p, p) in formatted_policies.into_iter().zip(policies.into_iter()) { + for ((f_p_id, f_p), (p_id, p)) in formatted_policies.into_iter().zip(policies.into_iter()) { + if f_p_id != p_id { + return Err(miette!( + "formatter changed the policy id from {p_id} to {f_p_id}" + )); + } let (f_anno, anno) = ( f_p.annotations() .map(|(k, v)| (k, &v.val)) @@ -59,8 +76,12 @@ fn soundness_check(ps: &str, ast: &PolicySet) -> Result<()> { .map(|(k, v)| (k, &v.val)) .collect::>(), ); - if !(f_anno == anno - && f_p.effect() == p.effect() + if f_anno != anno { + return Err(miette!( + "formatter changed the annotations from {anno:?} to {f_anno:?}" + )); + } + if !(f_p.effect() == p.effect() && f_p.principal_constraint() == p.principal_constraint() && f_p.action_constraint() == p.action_constraint() && f_p.resource_constraint() == p.resource_constraint() @@ -69,7 +90,7 @@ fn soundness_check(ps: &str, ast: &PolicySet) -> Result<()> { .eq_shape(p.non_head_constraints())) { return Err(miette!( - "policies differ in meaning or annotations:\noriginal: {p}\nformatted: {f_p}" + "formatter changed the policy structure:\noriginal:\n{p}\nformatted:\n{f_p}" )); } } @@ -124,7 +145,9 @@ pub fn policies_str_to_pretty(ps: &str, config: &Config) -> Result { } }; // add soundness check to make sure formatting doesn't alter policy ASTs - soundness_check(&formatted_policies, &ast)?; + soundness_check(&formatted_policies, &ast).wrap_err( + "internal error: please file an issue at ", + )?; Ok(formatted_policies) } @@ -167,6 +190,49 @@ mod tests { ); } + #[test] + fn test_soundness_check() { + let p1 = r#"permit (principal, action, resource) + when { " + + a + " };"#; + let p2 = r#"permit (principal, action, resource) + when { " + a + " };"#; + assert!(soundness_check(p2, &parse_policyset(p1).unwrap()).is_err()); + + let p1 = r#" + permit (principal, action, resource) + when { "a"}; + permit (principal, action, resource) + when { " + + a + " };"#; + let p2 = r#" + permit (principal, action, resource) + when { " + a + " }; + permit (principal, action, resource) + when { "a"};"#; + assert!(soundness_check(p2, &parse_policyset(p1).unwrap()).is_err()); + + let p1 = r#" + permit (principal, action, resource) + when { "a" }; + permit (principal, action, resource) + when { "b" };"#; + let p2 = r#" + permit (principal, action, resource) + when { "a" }; + permit (principal, action, resource) + when { "b"};"#; + assert!(soundness_check(p2, &parse_policyset(p1).unwrap()).is_ok()); + } + #[test] fn test_format_files() { use std::fs::read_to_string; diff --git a/cedar-policy-validator/Cargo.toml b/cedar-policy-validator/Cargo.toml index 1e4cd0c9a..37e60a0d8 100644 --- a/cedar-policy-validator/Cargo.toml +++ b/cedar-policy-validator/Cargo.toml @@ -2,7 +2,7 @@ name = "cedar-policy-validator" edition = "2021" -version = "3.1.3" +version = "3.1.4" license = "Apache-2.0" categories = ["compilers", "config"] description = "Validator for the Cedar Policy language." @@ -11,7 +11,7 @@ homepage = "https://cedarpolicy.com" repository = "https://github.com/cedar-policy/cedar" [dependencies] -cedar-policy-core = { version = "=3.1.3", path = "../cedar-policy-core" } +cedar-policy-core = { version = "=3.1.4", path = "../cedar-policy-core" } serde = { version = "1.0", features = ["derive"] } serde_json = { version = "1.0", features = ["preserve_order"] } serde_with = "3.0" diff --git a/cedar-policy/CHANGELOG.md b/cedar-policy/CHANGELOG.md index 059bc0871..20b0e44d3 100644 --- a/cedar-policy/CHANGELOG.md +++ b/cedar-policy/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [3.1.4] - 2024-05-17 + +### Fixed + +- The formatter will now fail with an error if it changes a policy's semantics. (#865) + ## [3.1.3] - 2024-04-15 ### Changed @@ -423,7 +429,8 @@ Cedar Language Version: 2.0.0 Cedar Language Version: 2.0.0 - Initial release of `cedar-policy`. -[Unreleased]: https://github.com/cedar-policy/cedar/compare/v3.1.3...main +[Unreleased]: https://github.com/cedar-policy/cedar/compare/v3.1.4...main +[3.1.4]: https://github.com/cedar-policy/cedar/compare/v3.1.3...v3.1.4 [3.1.3]: https://github.com/cedar-policy/cedar/compare/v3.1.2...v3.1.3 [3.1.2]: https://github.com/cedar-policy/cedar/compare/v3.1.1...v3.1.2 [3.1.1]: https://github.com/cedar-policy/cedar/compare/v3.1.0...v3.1.1 diff --git a/cedar-policy/Cargo.toml b/cedar-policy/Cargo.toml index 1c8b2bef1..6455ba044 100644 --- a/cedar-policy/Cargo.toml +++ b/cedar-policy/Cargo.toml @@ -2,7 +2,7 @@ name = "cedar-policy" edition = "2021" -version = "3.1.3" +version = "3.1.4" 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." @@ -11,8 +11,8 @@ homepage = "https://cedarpolicy.com" repository = "https://github.com/cedar-policy/cedar" [dependencies] -cedar-policy-core = { version = "=3.1.3", path = "../cedar-policy-core" } -cedar-policy-validator = { version = "=3.1.3", path = "../cedar-policy-validator" } +cedar-policy-core = { version = "=3.1.4", path = "../cedar-policy-core" } +cedar-policy-validator = { version = "=3.1.4", path = "../cedar-policy-validator" } ref-cast = "1.0" serde = { version = "1.0", features = ["derive", "rc"] } serde_json = "1.0"