#![allow(clippy::expect_used, reason = "tests")]
#![allow(clippy::unwrap_used, reason = "tests")]
use std::collections::HashMap;
use std::path::{Path, PathBuf};
use cedar_policy::EvalResult;
use cedar_policy::SlotId;
use cedar_policy_cli::{
authorize, check_parse, evaluate, link, run_tests, validate, Arguments, AuthorizeArgs,
CedarExitCode, CheckParseArgs, EvaluateArgs, LinkArgs, OptionalPoliciesArgs,
OptionalSchemaArgs, PoliciesArgs, PolicyFormat, RequestArgs, RunTestsArgs, SchemaArgs,
SchemaFormat, ValidateArgs,
};
use assert_cmd::cargo;
use predicates::prelude::*;
use rstest::rstest;
#[track_caller]
fn run_check_parse_test(
policies_file: impl Into<String>,
schema_file: impl Into<PathBuf>,
entities_file: Option<impl Into<PathBuf>>,
expected_exit_code: CedarExitCode,
) {
let cmd = CheckParseArgs {
policies: OptionalPoliciesArgs {
policies_file: Some(policies_file.into()),
policy_format: PolicyFormat::Cedar,
template_linked_file: None,
},
expression: None,
schema: OptionalSchemaArgs {
schema_file: Some(schema_file.into()),
schema_format: SchemaFormat::Cedar,
},
entities_file: entities_file.map(Into::into),
};
let output = check_parse(&cmd);
assert_eq!(output, expected_exit_code, "{cmd:#?}");
}
#[track_caller]
fn run_authorize_test(
policies_file: impl Into<String>,
entities_file: impl Into<String>,
principal: impl Into<String>,
action: impl Into<String>,
resource: impl Into<String>,
exit_code: CedarExitCode,
) {
run_authorize_test_with_linked_policies(
policies_file,
entities_file,
None::<String>,
principal,
action,
resource,
exit_code,
);
}
#[track_caller]
fn run_authorize_test_with_linked_policies(
policies_file: impl Into<String>,
entities_file: impl Into<String>,
links_file: Option<impl Into<String>>,
principal: impl Into<String>,
action: impl Into<String>,
resource: impl Into<String>,
exit_code: CedarExitCode,
) {
let cmd = AuthorizeArgs {
request: RequestArgs {
principal: Some(principal.into()),
action: Some(action.into()),
resource: Some(resource.into()),
context_json_file: None,
request_json_file: None,
request_validation: true,
},
policies: PoliciesArgs {
policies_file: Some(policies_file.into()),
policy_format: PolicyFormat::Cedar,
template_linked_file: links_file.map(Into::into),
},
schema: OptionalSchemaArgs {
schema_file: None,
schema_format: SchemaFormat::default(),
},
entities_file: entities_file.into(),
verbose: true,
timing: false,
};
let output = authorize(&cmd);
assert_eq!(exit_code, output, "{cmd:#?}",);
}
#[track_caller]
fn run_link_test(
policies_file: impl Into<String>,
links_file: impl Into<String>,
template_id: impl Into<String>,
linked_id: impl Into<String>,
env: impl IntoIterator<Item = (SlotId, String)>,
expected: CedarExitCode,
) {
let cmd = LinkArgs {
policies: PoliciesArgs {
policies_file: Some(policies_file.into()),
policy_format: PolicyFormat::Cedar,
template_linked_file: Some(links_file.into()),
},
template_id: template_id.into(),
new_id: linked_id.into(),
arguments: Arguments {
data: HashMap::from_iter(env),
},
};
let output = link(&cmd);
assert_eq!(output, expected);
}
#[track_caller]
fn run_authorize_test_context(
policies_file: impl Into<String>,
entities_file: impl Into<String>,
principal: impl Into<String>,
action: impl Into<String>,
resource: impl Into<String>,
context_file: impl Into<String>,
exit_code: CedarExitCode,
) {
let cmd = AuthorizeArgs {
request: RequestArgs {
principal: Some(principal.into()),
action: Some(action.into()),
resource: Some(resource.into()),
context_json_file: Some(context_file.into()),
request_json_file: None,
request_validation: true,
},
policies: PoliciesArgs {
policies_file: Some(policies_file.into()),
policy_format: PolicyFormat::Cedar,
template_linked_file: None,
},
schema: OptionalSchemaArgs {
schema_file: None,
schema_format: SchemaFormat::default(),
},
entities_file: entities_file.into(),
verbose: true,
timing: false,
};
let output = authorize(&cmd);
assert_eq!(exit_code, output, "{cmd:#?}",);
}
#[track_caller]
fn run_authorize_test_json(
policies_file: impl Into<String>,
entities_file: impl Into<String>,
request_json_file: impl Into<String>,
exit_code: CedarExitCode,
) {
let cmd = AuthorizeArgs {
request: RequestArgs {
principal: None,
action: None,
resource: None,
context_json_file: None,
request_json_file: Some(request_json_file.into()),
request_validation: true,
},
policies: PoliciesArgs {
policies_file: Some(policies_file.into()),
policy_format: PolicyFormat::Cedar,
template_linked_file: None,
},
schema: OptionalSchemaArgs {
schema_file: None,
schema_format: SchemaFormat::default(),
},
entities_file: entities_file.into(),
verbose: true,
timing: false,
};
let output = authorize(&cmd);
assert_eq!(exit_code, output, "{cmd:#?}",);
}
#[test]
fn test_authorize_samples() {
run_check_parse_test(
"sample-data/sandbox_a/policies_1.cedar",
"sample-data/sandbox_a/schema.cedarschema",
None::<PathBuf>,
CedarExitCode::Success,
);
run_authorize_test(
"sample-data/sandbox_a/policies_1.cedar",
"sample-data/sandbox_a/entities.json",
"User::\"alice\"",
"Action::\"view\"",
"Photo::\"VacationPhoto94.jpg\"",
CedarExitCode::Success,
);
run_check_parse_test(
"sample-data/sandbox_a/policies_2.cedar",
"sample-data/sandbox_a/schema.cedarschema",
None::<PathBuf>,
CedarExitCode::Success,
);
run_authorize_test(
"sample-data/sandbox_a/policies_2.cedar",
"sample-data/sandbox_a/entities.json",
"User::\"alice\"",
"Action::\"view\"",
"Photo::\"VacationPhoto94.jpg\"",
CedarExitCode::Success,
);
run_authorize_test(
"sample-data/sandbox_a/policies_2.cedar",
"sample-data/sandbox_a/entities.json",
"User::\"alice\"",
"Action::\"edit\"",
"Photo::\"VacationPhoto94.jpg\"",
CedarExitCode::Success,
);
run_authorize_test(
"sample-data/sandbox_a/policies_2.cedar",
"sample-data/sandbox_a/entities.json",
"User::\"alice\"",
"Action::\"delete\"",
"Photo::\"VacationPhoto94.jpg\"",
CedarExitCode::Success,
);
run_authorize_test(
"sample-data/sandbox_a/policies_2.cedar",
"sample-data/sandbox_a/entities.json",
"User::\"alice\"",
"Action::\"comment\"",
"Photo::\"VacationPhoto94.jpg\"",
CedarExitCode::AuthorizeDeny,
);
run_authorize_test(
"sample-data/sandbox_a/policies_2.cedar",
"sample-data/sandbox_a/entities.json",
"User::\"bob\"",
"Action::\"view\"",
"Photo::\"VacationPhoto94.jpg\"",
CedarExitCode::Success,
);
run_authorize_test(
"sample-data/sandbox_a/policies_2.cedar",
"sample-data/sandbox_a/entities.json",
"User::\"bob\"",
"Action::\"edit\"",
"Photo::\"VacationPhoto94.jpg\"",
CedarExitCode::AuthorizeDeny,
);
run_authorize_test(
"sample-data/sandbox_a/policies_2.cedar",
"sample-data/sandbox_a/entities.json",
"User::\"bob\"",
"Action::\"delete\"",
"Photo::\"VacationPhoto94.jpg\"",
CedarExitCode::AuthorizeDeny,
);
run_authorize_test(
"sample-data/sandbox_a/policies_2.cedar",
"sample-data/sandbox_a/entities.json",
"User::\"bob\"",
"Action::\"comment\"",
"Photo::\"VacationPhoto94.jpg\"",
CedarExitCode::AuthorizeDeny,
);
run_check_parse_test(
"sample-data/sandbox_a/policies_3.cedar",
"sample-data/sandbox_a/schema.cedarschema",
None::<PathBuf>,
CedarExitCode::Success,
);
run_authorize_test(
"sample-data/sandbox_a/policies_3.cedar",
"sample-data/sandbox_a/entities.json",
"User::\"alice\"",
"Action::\"view\"",
"Photo::\"VacationPhoto94.jpg\"",
CedarExitCode::Success,
);
run_authorize_test(
"sample-data/sandbox_a/policies_3.cedar",
"sample-data/sandbox_a/entities.json",
"User::\"bob\"",
"Action::\"view\"",
"Photo::\"VacationPhoto94.jpg\"",
CedarExitCode::Success,
);
run_authorize_test(
"sample-data/sandbox_a/policies_3.cedar",
"sample-data/sandbox_a/entities.json",
"User::\"tim\"",
"Action::\"view\"",
"Photo::\"VacationPhoto94.jpg\"",
CedarExitCode::Success,
);
run_authorize_test(
"sample-data/sandbox_a/policies_3.cedar",
"sample-data/sandbox_a/entities.json",
"User::\"alice\"",
"Action::\"listPhotos\"",
"Album::\"jane_vacation\"",
CedarExitCode::Success,
);
run_authorize_test(
"sample-data/sandbox_a/policies_3.cedar",
"sample-data/sandbox_a/entities.json",
"User::\"bob\"",
"Action::\"listPhotos\"",
"Album::\"jane_vacation\"",
CedarExitCode::Success,
);
run_authorize_test(
"sample-data/sandbox_a/policies_3.cedar",
"sample-data/sandbox_a/entities.json",
"User::\"tim\"",
"Action::\"listPhotos\"",
"Album::\"jane_vacation\"",
CedarExitCode::Success,
);
run_check_parse_test(
"sample-data/sandbox_b/policies_4.cedar",
"sample-data/sandbox_b/schema.cedarschema",
None::<PathBuf>,
CedarExitCode::Success,
);
run_authorize_test(
"sample-data/sandbox_b/policies_4.cedar",
"sample-data/sandbox_b/entities.json",
"User::\"alice\"",
"Action::\"view\"",
"Photo::\"prototype_v0.jpg\"",
CedarExitCode::Success,
);
run_authorize_test(
"sample-data/sandbox_b/policies_4.cedar",
"sample-data/sandbox_b/entities.json",
"User::\"stacey\"",
"Action::\"view\"",
"Photo::\"prototype_v0.jpg\"",
CedarExitCode::AuthorizeDeny,
);
run_authorize_test(
"sample-data/sandbox_b/policies_4.cedar",
"sample-data/sandbox_b/entities.json",
"User::\"ahmad\"",
"Action::\"view\"",
"Photo::\"prototype_v0.jpg\"",
CedarExitCode::AuthorizeDeny,
);
run_authorize_test(
"sample-data/sandbox_b/policies_5.cedar",
"sample-data/sandbox_b/entities.json",
"User::\"stacey\"",
"Action::\"view\"",
"Photo::\"alice_w2.jpg\"",
CedarExitCode::AuthorizeDeny,
);
run_check_parse_test(
"sample-data/sandbox_b/policies_5.cedar",
"sample-data/sandbox_b/schema.cedarschema",
None::<PathBuf>,
CedarExitCode::Success,
);
run_authorize_test(
"sample-data/sandbox_b/policies_5.cedar",
"sample-data/sandbox_b/entities.json",
"User::\"alice\"",
"Action::\"view\"",
"Photo::\"alice_w2.jpg\"",
CedarExitCode::Success,
);
run_authorize_test(
"sample-data/sandbox_b/policies_5.cedar",
"sample-data/sandbox_b/entities.json",
"User::\"stacey\"",
"Action::\"view\"",
"Photo::\"vacation.jpg\"",
CedarExitCode::Success,
);
run_authorize_test_context(
"sample-data/sandbox_b/policies_6.cedar",
"sample-data/sandbox_b/entities.json",
"User::\"alice\"",
"Action::\"view\"",
"Photo::\"vacation.jpg\"",
"sample-data/sandbox_b/doesnotexist.json",
CedarExitCode::Failure,
);
run_authorize_test_context(
"sample-data/sandbox_b/policies_6.cedar",
"sample-data/sandbox_b/entities.json",
"User::\"alice\"",
"Action::\"view\"",
"Photo::\"vacation.jpg\"",
"sample-data/sandbox_b/context.json",
CedarExitCode::Success,
);
run_authorize_test_context(
"sample-data/sandbox_b/policies_6.cedar",
"sample-data/sandbox_b/entities.json",
"User::\"alice\"",
"Action::\"view\"",
"Photo::\"vacation.jpg\"",
"sample-data/sandbox_b/context_deny.json",
CedarExitCode::AuthorizeDeny,
);
run_authorize_test_json(
"sample-data/tiny_sandboxes/sample1/policy.cedar",
"sample-data/tiny_sandboxes/sample1/entity.json",
"sample-data/tiny_sandboxes/sample1/request.json",
CedarExitCode::Success,
);
run_authorize_test_json(
"sample-data/tiny_sandboxes/sample2/policy.cedar",
"sample-data/tiny_sandboxes/sample2/entity.json",
"sample-data/tiny_sandboxes/sample2/request.json",
CedarExitCode::Success,
);
run_authorize_test_json(
"sample-data/tiny_sandboxes/sample3/policy.cedar",
"sample-data/tiny_sandboxes/sample3/entity.json",
"sample-data/tiny_sandboxes/sample3/request.json",
CedarExitCode::AuthorizeDeny,
);
run_authorize_test_json(
"sample-data/tiny_sandboxes/sample4/policy.cedar",
"sample-data/tiny_sandboxes/sample4/entity.json",
"sample-data/tiny_sandboxes/sample4/request.json",
CedarExitCode::Success,
);
run_authorize_test_json(
"sample-data/tiny_sandboxes/sample5/policy.cedar",
"sample-data/tiny_sandboxes/sample5/entity.json",
"sample-data/tiny_sandboxes/sample5/request.json",
CedarExitCode::Success,
);
run_authorize_test_json(
"sample-data/tiny_sandboxes/sample6/policy.cedar",
"sample-data/tiny_sandboxes/sample6/entity.json",
"sample-data/tiny_sandboxes/sample6/request.json",
CedarExitCode::AuthorizeDeny,
);
run_authorize_test_json(
"sample-data/tiny_sandboxes/sample7/policy.cedar",
"sample-data/tiny_sandboxes/sample7/entity.json",
"sample-data/tiny_sandboxes/sample7/request.json",
CedarExitCode::Success,
);
run_authorize_test_json(
"sample-data/tiny_sandboxes/sample8/policy.cedar",
"sample-data/tiny_sandboxes/sample8/entity.json",
"sample-data/tiny_sandboxes/sample8/request.json",
CedarExitCode::Success,
);
run_authorize_test_json(
"sample-data/tiny_sandboxes/sample9/policy.cedar",
"sample-data/tiny_sandboxes/sample9/entity.json",
"sample-data/tiny_sandboxes/sample9/request.json",
CedarExitCode::Success,
);
}
#[rstest]
#[case(
"sample-data/doesnotexist.cedar",
"sample-data/sandbox_a/schema.cedarschema.json",
CedarExitCode::Failure
)]
#[case(
"sample-data/sandbox_a/policies_1.cedar",
"sample-data/doesnotexist.json",
CedarExitCode::Failure
)]
#[case(
"sample-data/sandbox_a/policies_1.cedar",
"sample-data/sandbox_a/schema.cedarschema.json",
CedarExitCode::Success
)]
#[case(
"sample-data/sandbox_a/policies_1_bad.cedar",
"sample-data/sandbox_a/schema.cedarschema.json",
CedarExitCode::ValidationFailure
)]
#[case(
"sample-data/sandbox_a/policies_2.cedar",
"sample-data/sandbox_a/schema.cedarschema.json",
CedarExitCode::Success
)]
#[case(
"sample-data/sandbox_a/policies_3.cedar",
"sample-data/sandbox_a/schema.cedarschema.json",
CedarExitCode::Success
)]
#[case(
"sample-data/sandbox_b/policies_4.cedar",
"sample-data/sandbox_b/schema.cedarschema.json",
CedarExitCode::Success
)]
#[case(
"sample-data/sandbox_b/policies_5_bad.cedar",
"sample-data/sandbox_b/schema.cedarschema.json",
CedarExitCode::ValidationFailure
)]
#[case(
"sample-data/sandbox_b/policies_5.cedar",
"sample-data/sandbox_b/schema.cedarschema.json",
CedarExitCode::Success
)]
#[case(
"sample-data/sandbox_b/policies_6.cedar",
"sample-data/sandbox_b/schema.cedarschema.json",
CedarExitCode::Success
)]
#[case(
"sample-data/tiny_sandboxes/sample1/policy.cedar",
"sample-data/tiny_sandboxes/sample1/schema.cedarschema.json",
CedarExitCode::Success
)]
#[case(
"sample-data/tiny_sandboxes/sample2/policy.cedar",
"sample-data/tiny_sandboxes/sample2/schema.cedarschema.json",
CedarExitCode::Success
)]
#[case(
"sample-data/tiny_sandboxes/sample3/policy.cedar",
"sample-data/tiny_sandboxes/sample3/schema.cedarschema.json",
CedarExitCode::Success
)]
#[case(
"sample-data/tiny_sandboxes/sample4/policy.cedar",
"sample-data/tiny_sandboxes/sample4/schema.cedarschema.json",
CedarExitCode::Success
)]
#[case(
"sample-data/tiny_sandboxes/sample5/policy.cedar",
"sample-data/tiny_sandboxes/sample5/schema.cedarschema.json",
CedarExitCode::Success
)]
#[case(
"sample-data/tiny_sandboxes/sample6/policy.cedar",
"sample-data/tiny_sandboxes/sample6/schema.cedarschema.json",
CedarExitCode::Success
)]
#[case(
"sample-data/tiny_sandboxes/sample7/policy.cedar",
"sample-data/tiny_sandboxes/sample7/schema.cedarschema.json",
CedarExitCode::Success
)]
#[case(
"sample-data/tiny_sandboxes/sample8/policy.cedar",
"sample-data/tiny_sandboxes/sample8/schema.cedarschema.json",
CedarExitCode::Success
)]
#[case(
"sample-data/tiny_sandboxes/sample9/policy.cedar",
"sample-data/tiny_sandboxes/sample9/schema.cedarschema.json",
CedarExitCode::Success
)]
#[case(
"sample-data/tiny_sandboxes/sample9/policy_bad.cedar",
"sample-data/tiny_sandboxes/sample9/schema.cedarschema.json",
CedarExitCode::ValidationFailure
)]
#[track_caller]
fn test_validate_samples(
#[case] policies_file: impl Into<String>,
#[case] schema_file: impl AsRef<Path>,
#[case] exit_code: CedarExitCode,
) {
let policies_file = policies_file.into();
let schema_file = schema_file.as_ref();
let cmd = ValidateArgs {
schema: SchemaArgs {
schema_file: schema_file.into(),
schema_format: SchemaFormat::Json,
},
policies: PoliciesArgs {
policies_file: Some(policies_file.clone()),
policy_format: PolicyFormat::Cedar,
template_linked_file: None,
},
deny_warnings: false,
validation_mode: cedar_policy_cli::ValidationMode::Strict,
level: None,
};
let output = validate(&cmd);
assert_eq!(exit_code, output, "{cmd:#?}");
let cmd = ValidateArgs {
schema: SchemaArgs {
schema_file: schema_file.with_extension(""), schema_format: SchemaFormat::Cedar,
},
policies: PoliciesArgs {
policies_file: Some(policies_file),
policy_format: PolicyFormat::Cedar,
template_linked_file: None,
},
deny_warnings: false,
validation_mode: cedar_policy_cli::ValidationMode::Strict,
level: None,
};
let output = validate(&cmd);
assert_eq!(exit_code, output, "{cmd:#?}")
}
#[rstest]
#[case(
"sample-data/tiny_sandboxes/level-validation/policy-level-0.cedar",
"sample-data/tiny_sandboxes/level-validation/schema.cedarschema",
0,
CedarExitCode::Success
)]
#[case(
"sample-data/tiny_sandboxes/level-validation/policy-level-1.cedar",
"sample-data/tiny_sandboxes/level-validation/schema.cedarschema",
0,
CedarExitCode::ValidationFailure
)]
#[case(
"sample-data/tiny_sandboxes/level-validation/policy-level-1.cedar",
"sample-data/tiny_sandboxes/level-validation/schema.cedarschema",
1,
CedarExitCode::Success
)]
#[case(
"sample-data/tiny_sandboxes/level-validation/policy-level-1.cedar",
"sample-data/tiny_sandboxes/level-validation/schema.cedarschema",
0,
CedarExitCode::ValidationFailure
)]
#[case(
"sample-data/tiny_sandboxes/level-validation/policy-level-1.cedar",
"sample-data/tiny_sandboxes/level-validation/schema.cedarschema",
1,
CedarExitCode::Success
)]
#[case(
"sample-data/tiny_sandboxes/level-validation/policy-level-2.cedar",
"sample-data/tiny_sandboxes/level-validation/schema.cedarschema",
0,
CedarExitCode::ValidationFailure
)]
#[case(
"sample-data/tiny_sandboxes/level-validation/policy-level-2.cedar",
"sample-data/tiny_sandboxes/level-validation/schema.cedarschema",
1,
CedarExitCode::ValidationFailure
)]
#[case(
"sample-data/tiny_sandboxes/level-validation/policy-level-2.cedar",
"sample-data/tiny_sandboxes/level-validation/schema.cedarschema",
2,
CedarExitCode::Success
)]
#[track_caller]
fn test_level_validate_samples(
#[case] policies_file: impl Into<String>,
#[case] schema_file: impl AsRef<Path>,
#[case] level: u32,
#[case] exit_code: CedarExitCode,
) {
let policies_file = policies_file.into();
let schema_file = schema_file.as_ref();
let cmd = ValidateArgs {
schema: SchemaArgs {
schema_file: schema_file.into(),
schema_format: SchemaFormat::Cedar,
},
policies: PoliciesArgs {
policies_file: Some(policies_file),
policy_format: PolicyFormat::Cedar,
template_linked_file: None,
},
deny_warnings: false,
validation_mode: cedar_policy_cli::ValidationMode::Strict,
level: Some(level),
};
let output = validate(&cmd);
assert_eq!(exit_code, output, "{cmd:#?}");
}
#[rstest]
#[case(
"sample-data/tiny_sandboxes/sample1/doesnotexist.json",
"sample-data/tiny_sandboxes/sample1/entity.json",
"principal in UserGroup::\"jane_friends\"",
CedarExitCode::Failure,
EvalResult::Bool(false)
)]
#[case(
"sample-data/tiny_sandboxes/sample1/request.json",
"sample-data/tiny_sandboxes/sample1/doesnotexist.json",
"principal in UserGroup::\"jane_friends\"",
CedarExitCode::Failure,
EvalResult::Bool(false)
)]
#[case(
"sample-data/tiny_sandboxes/sample1/request.json",
"sample-data/tiny_sandboxes/sample1/entity.json",
"parse error",
CedarExitCode::Failure,
EvalResult::Bool(false)
)]
#[case(
"sample-data/tiny_sandboxes/sample1/request.json",
"sample-data/tiny_sandboxes/sample1/entity.json",
"1 + \"type error\"",
CedarExitCode::Failure,
EvalResult::Bool(false)
)]
#[case(
"sample-data/tiny_sandboxes/sample1/request.json",
"sample-data/tiny_sandboxes/sample1/entity.json",
"principal in UserGroup::\"jane_friends\"",
CedarExitCode::Success,
EvalResult::Bool(true)
)]
#[case(
"sample-data/tiny_sandboxes/sample1/request.json",
"sample-data/tiny_sandboxes/sample1/entity.json",
"[\"a\",true,10].contains(10)",
CedarExitCode::Success,
EvalResult::Bool(true)
)]
#[case(
"sample-data/tiny_sandboxes/sample1/request.json",
"sample-data/tiny_sandboxes/sample1/entity.json",
"principal.age >= 17",
CedarExitCode::Success,
EvalResult::Bool(true)
)]
#[case("sample-data/tiny_sandboxes/sample2/request.json",
"sample-data/tiny_sandboxes/sample2/entity.json",
"resource.owner",
CedarExitCode::Success,
EvalResult::EntityUid("User::\"bob\"".parse().unwrap()),)]
#[case("sample-data/tiny_sandboxes/sample3/request.json",
"sample-data/tiny_sandboxes/sample3/entity.json",
"if 10 > 5 then \"good\" else \"bad\"",
CedarExitCode::Success,
EvalResult::String("good".to_owned()),)]
#[case(
"sample-data/tiny_sandboxes/sample4/request.json",
"sample-data/tiny_sandboxes/sample4/entity.json",
"resource.owner == User::\"bob\"",
CedarExitCode::Success,
EvalResult::Bool(true)
)]
#[case(
"sample-data/tiny_sandboxes/sample5/request.json",
"sample-data/tiny_sandboxes/sample5/entity.json",
"principal.addr.isLoopback()",
CedarExitCode::Success,
EvalResult::Bool(true)
)]
#[case(
"sample-data/tiny_sandboxes/sample6/request.json",
"sample-data/tiny_sandboxes/sample6/entity.json",
"principal.account.age >= 17",
CedarExitCode::Success,
EvalResult::Bool(true)
)]
#[case(
"sample-data/tiny_sandboxes/sample7/request.json",
"sample-data/tiny_sandboxes/sample7/entity.json",
"context.role.contains(\"admin\")",
CedarExitCode::Success,
EvalResult::Bool(true)
)]
fn test_evaluate_samples(
#[case] request_json_file: impl Into<String>,
#[case] entities_file: impl Into<String>,
#[case] expression: impl Into<String>,
#[case] exit_code: CedarExitCode,
#[case] expected: EvalResult,
) {
let cmd = EvaluateArgs {
schema: OptionalSchemaArgs {
schema_file: None,
schema_format: SchemaFormat::default(),
},
entities_file: Some(entities_file.into()),
request: RequestArgs {
principal: None,
action: None,
resource: None,
context_json_file: None,
request_json_file: Some(request_json_file.into()),
request_validation: true,
},
expression: expression.into(),
};
let output = evaluate(&cmd);
assert_eq!(exit_code, output.0, "{cmd:#?}",);
assert_eq!(expected, output.1, "{cmd:#?}",);
}
#[test]
fn test_link_samples() {
run_authorize_test(
"sample-data/sandbox_c/doesnotexist.cedar",
"sample-data/sandbox_c/entities.json",
"User::\"alice\"",
"Action::\"view\"",
"Photo::\"VacationPhoto94.jpg\"",
CedarExitCode::Failure,
);
run_authorize_test(
"sample-data/sandbox_c/policies.cedar",
"sample-data/sandbox_c/doesnotexist.json",
"User::\"alice\"",
"Action::\"view\"",
"Photo::\"VacationPhoto94.jpg\"",
CedarExitCode::Failure,
);
run_authorize_test(
"sample-data/sandbox_c/policies.cedar",
"sample-data/sandbox_c/entities.json",
"invalid",
"Action::\"view\"",
"Photo::\"VacationPhoto94.jpg\"",
CedarExitCode::Failure,
);
run_authorize_test(
"sample-data/sandbox_c/policies.cedar",
"sample-data/sandbox_c/entities.json",
"User::\"alice\"",
"invalid",
"Photo::\"VacationPhoto94.jpg\"",
CedarExitCode::Failure,
);
run_authorize_test(
"sample-data/sandbox_c/policies.cedar",
"sample-data/sandbox_c/entities.json",
"User::\"alice\"",
"Action::\"view\"",
"invalid",
CedarExitCode::Failure,
);
run_authorize_test(
"sample-data/sandbox_c/policies.cedar",
"sample-data/sandbox_c/entities.json",
"User::\"alice\"",
"Action::\"view\"",
"Photo::\"VacationPhoto94.jpg\"",
CedarExitCode::AuthorizeDeny,
);
run_authorize_test(
"sample-data/sandbox_c/policies.cedar",
"sample-data/sandbox_c/entities.json",
"User::\"bob\"",
"Action::\"view\"",
"Photo::\"VacationPhoto94.jpg\"",
CedarExitCode::AuthorizeDeny,
);
let linked_file = tempfile::NamedTempFile::new().expect("Failed to create linked file");
let linked_file_name = linked_file.path().as_os_str().to_string_lossy().to_string();
run_link_test(
"sample-data/sandbox_c/doesnotexist.cedar",
&linked_file_name,
"AccessVacation",
"AliceAccess",
[(SlotId::principal(), "User::\"alice\"".to_string())],
CedarExitCode::Failure,
);
run_link_test(
"sample-data/sandbox_c/policies.cedar",
&linked_file_name,
"AccessVacation",
"AliceAccess",
[(SlotId::principal(), "invalid".to_string())],
CedarExitCode::Failure,
);
run_link_test(
"sample-data/sandbox_c/policies.cedar",
&linked_file_name,
"AccessVacation",
"AliceAccess",
[(SlotId::principal(), "User::\"alice\"".to_string())],
CedarExitCode::Success,
);
run_authorize_test_with_linked_policies(
"sample-data/sandbox_c/policies.cedar",
"sample-data/sandbox_c/entities.json",
Some(&linked_file_name),
"User::\"alice\"",
"Action::\"view\"",
"Photo::\"VacationPhoto94.jpg\"",
CedarExitCode::Success,
);
run_authorize_test_with_linked_policies(
"sample-data/sandbox_c/policies.cedar",
"sample-data/sandbox_c/entities.json",
Some(&linked_file_name),
"User::\"bob\"",
"Action::\"view\"",
"Photo::\"VacationPhoto94.jpg\"",
CedarExitCode::AuthorizeDeny,
);
run_link_test(
"sample-data/sandbox_c/policies.cedar",
&linked_file_name,
"AccessVacation",
"BobAccess",
[(SlotId::principal(), "User::\"bob\"".to_string())],
CedarExitCode::Success,
);
run_authorize_test_with_linked_policies(
"sample-data/sandbox_c/policies.cedar",
"sample-data/sandbox_c/entities.json",
Some(&linked_file_name),
"User::\"alice\"",
"Action::\"view\"",
"Photo::\"VacationPhoto94.jpg\"",
CedarExitCode::Success,
);
run_authorize_test_with_linked_policies(
"sample-data/sandbox_c/policies.cedar",
"sample-data/sandbox_c/entities.json",
Some(&linked_file_name),
"User::\"bob\"",
"Action::\"view\"",
"Photo::\"VacationPhoto94.jpg\"",
CedarExitCode::Success,
);
run_authorize_test_with_linked_policies(
"sample-data/sandbox_c/policies_edited.cedar",
"sample-data/sandbox_c/entities.json",
Some(&linked_file_name),
"User::\"alice\"",
"Action::\"view\"",
"Photo::\"VacationPhoto94.jpg\"",
CedarExitCode::AuthorizeDeny,
);
run_authorize_test_with_linked_policies(
"sample-data/sandbox_c/policies_edited.cedar",
"sample-data/sandbox_c/entities.json",
Some(&linked_file_name),
"User::\"bob\"",
"Action::\"view\"",
"Photo::\"VacationPhoto94.jpg\"",
CedarExitCode::Success,
);
}
#[rstest]
#[track_caller]
fn test_format_samples(#[files("sample-data/**/polic*.cedar")] path: PathBuf) {
let policies_file = path.to_str().unwrap();
let original = std::fs::read_to_string(policies_file).unwrap();
let format_cmd = cargo::cargo_bin_cmd!("cedar")
.arg("format")
.arg("-p")
.arg(policies_file)
.assert();
let formatted =
std::str::from_utf8(&format_cmd.get_output().stdout).expect("output should be decodable");
assert_eq!(
original, formatted,
"\noriginal:\n{original}\n\nformatted:\n{formatted}",
);
}
#[test]
fn test_format_write() {
const POLICY_SOURCE: &str = "sample-data/tiny_sandboxes/format/unformatted.cedar";
let tmp_dir = env!("CARGO_TARGET_TMPDIR");
let unformatted_file = format!("{tmp_dir}/unformatted.cedar");
std::fs::copy(POLICY_SOURCE, &unformatted_file).unwrap();
let original = std::fs::read_to_string(&unformatted_file).unwrap();
cargo::cargo_bin_cmd!("cedar")
.arg("format")
.arg("-p")
.arg(&unformatted_file)
.assert()
.success();
let formatted = std::fs::read_to_string(&unformatted_file).unwrap();
assert_eq!(
original, formatted,
"original and formatted should be the same without -w\noriginal:{original}\n\nformatted:{formatted}"
);
cargo::cargo_bin_cmd!("cedar")
.arg("format")
.arg("-p")
.arg(&unformatted_file)
.arg("-w")
.assert()
.success();
let formatted = std::fs::read_to_string(&unformatted_file).unwrap();
assert_ne!(
original, formatted,
"original and formatted should differ under -w\noriginal:{original}\n\nformatted:{formatted}"
);
}
#[test]
fn test_format_check() {
const POLICY_REQUIRING_FORMAT: &str = "sample-data/tiny_sandboxes/format/unformatted.cedar";
const POLICY_ALREADY_FORMATTED: &str = "sample-data/tiny_sandboxes/format/formatted.cedar";
cargo::cargo_bin_cmd!("cedar")
.arg("format")
.arg("-p")
.arg(POLICY_REQUIRING_FORMAT)
.arg("-c")
.assert()
.code(1);
cargo::cargo_bin_cmd!("cedar")
.arg("format")
.arg("-p")
.arg(POLICY_ALREADY_FORMATTED)
.arg("-c")
.assert()
.code(0);
}
#[test]
fn test_write_check_are_mutually_exclusive() {
const POLICY_SOURCE: &str = "sample-data/tiny_sandboxes/format/unformatted.cedar";
cargo::cargo_bin_cmd!("cedar")
.arg("format")
.arg("-p")
.arg(POLICY_SOURCE)
.arg("-w")
.arg("-c")
.assert()
.failure()
.stderr(predicates::str::contains(
"the argument '--write' cannot be used with '--check'",
));
}
#[test]
fn test_require_policies_for_write() {
cargo::cargo_bin_cmd!("cedar")
.arg("format")
.arg("-w")
.write_stdin("permit (principal, action, resource);")
.assert()
.failure()
.stderr(predicates::str::contains(
"the following required arguments were not provided:\n --policies <FILE>",
));
}
#[test]
fn test_check_parse_json_static_policy() {
let json_policy: &str = "sample-data/tiny_sandboxes/json-check-parse/static_policy.cedar.json";
cargo::cargo_bin_cmd!("cedar")
.arg("check-parse")
.arg("--policy-format")
.arg("json")
.arg("-p")
.arg(json_policy)
.assert()
.code(0);
}
#[test]
fn test_check_parse_json_policy_template() {
let json_policy: &str =
"sample-data/tiny_sandboxes/json-check-parse/policy_template.cedar.json";
cargo::cargo_bin_cmd!("cedar")
.arg("check-parse")
.arg("--policy-format")
.arg("json")
.arg("-p")
.arg(json_policy)
.assert()
.code(0);
}
#[test]
fn test_check_parse_json_policy_set() {
let json_policy: &str = "sample-data/tiny_sandboxes/json-check-parse/policy_set.cedar.json";
cargo::cargo_bin_cmd!("cedar")
.arg("check-parse")
.arg("--policy-format")
.arg("json")
.arg("-p")
.arg(json_policy)
.assert()
.code(0);
}
#[test]
fn test_check_parse_json_policy_mixed_properties() {
let json_policy: &str =
"sample-data/tiny_sandboxes/json-check-parse/policy_mixed_properties.cedar.json";
cargo::cargo_bin_cmd!("cedar")
.arg("check-parse")
.arg("--policy-format")
.arg("json")
.arg("-p")
.arg(json_policy)
.assert()
.code(1)
.stdout(predicate::str::contains(
"matching properties from both formats",
));
}
#[test]
fn test_check_parse_json_policy_no_matching_properties() {
let json_policy: &str =
"sample-data/tiny_sandboxes/json-check-parse/policy_no_matching_properties.cedar.json";
cargo::cargo_bin_cmd!("cedar")
.arg("check-parse")
.arg("--policy-format")
.arg("json")
.arg("-p")
.arg(json_policy)
.assert()
.code(1)
.stdout(predicate::str::contains("no matching properties"));
}
#[test]
fn test_authorize_json_policy() {
let json_policy: &str = "sample-data/tiny_sandboxes/json-authorize/policy.cedar.json";
let entities: &str = "sample-data/tiny_sandboxes/json-authorize/entity.json";
cargo::cargo_bin_cmd!("cedar")
.arg("authorize")
.arg("--policy-format")
.arg("json")
.arg("-p")
.arg(json_policy)
.arg("--entities")
.arg(entities)
.arg("--principal")
.arg(r#"User::"bob""#)
.arg("--action")
.arg(r#"Action::"view""#)
.arg("--resource")
.arg(r#"Photo::"VacationPhoto94.jpg""#)
.assert()
.code(0);
}
#[test]
fn test_translate_policy() {
let cedar_filename = "sample-data/tiny_sandboxes/translate-policy/policy.cedar";
let json_filename = "sample-data/tiny_sandboxes/translate-policy/policy.cedar.json";
let cedar = std::fs::read_to_string(cedar_filename).unwrap();
let json = std::fs::read_to_string(json_filename).unwrap();
let to_json_command = cargo::cargo_bin_cmd!("cedar")
.arg("translate-policy")
.arg("--direction")
.arg("cedar-to-json")
.arg("-p")
.arg(cedar_filename)
.assert();
let translated_json = std::str::from_utf8(&to_json_command.get_output().stdout)
.expect("output should be decodable");
assert_eq!(
translated_json, json,
"\noriginal:\n{cedar}\n\ttranslated:\n{translated_json}",
);
let translate_to_cedar = cargo::cargo_bin_cmd!("cedar")
.arg("translate-policy")
.arg("--direction")
.arg("json-to-cedar")
.arg("-p")
.arg(json_filename)
.assert();
let translated_cedar = std::str::from_utf8(&translate_to_cedar.get_output().stdout)
.expect("output should be decodable");
let expected_translated_cedar = r#"permit(
principal == User::"alice",
action == Action::"update",
resource == Photo::"VacationPhoto94.jpg"
);
"#;
assert_eq!(
translated_cedar, expected_translated_cedar,
"\noriginal:\n{cedar}\n\ttranslated:\n{translated_cedar}",
);
}
#[test]
fn test_translate_schema() {
let cedar_filename = "sample-data/tiny_sandboxes/translate-schema/tinytodo.cedarschema";
let json_filename = "sample-data/tiny_sandboxes/translate-schema/tinytodo.cedarschema.json";
cargo::cargo_bin_cmd!("cedar")
.arg("translate-schema")
.arg("--direction")
.arg("cedar-to-json")
.arg("-s")
.arg(cedar_filename)
.assert()
.code(0);
cargo::cargo_bin_cmd!("cedar")
.arg("translate-schema")
.arg("--direction")
.arg("json-to-cedar")
.arg("-s")
.arg(json_filename)
.assert()
.code(0);
}
#[test]
fn test_translate_schema_with_resolved_types() {
let cedar_filename = "sample-data/tiny_sandboxes/translate-schema/tinytodo.cedarschema";
let output = cargo::cargo_bin_cmd!("cedar")
.arg("translate-schema")
.arg("--direction")
.arg("cedar-to-json-with-resolved-types")
.arg("-s")
.arg(cedar_filename)
.assert()
.code(0);
let json_output =
std::str::from_utf8(&output.get_output().stdout).expect("output should be decodable");
let parsed_json: serde_json::Value =
serde_json::from_str(json_output).expect("output should be valid JSON");
let json_str = serde_json::to_string(&parsed_json).unwrap();
assert!(
!json_str.contains("EntityOrCommon"),
"Output should not contain unresolved EntityOrCommon types: {}",
json_str
);
assert!(
json_str.contains("List"),
"Output should contain List entity type"
);
assert!(
json_str.contains("User"),
"Output should contain User entity type"
);
assert!(
json_str.contains("Team"),
"Output should contain Team entity type"
);
assert!(
json_str.contains("Application"),
"Output should contain Application entity type"
);
}
#[test]
fn test_translate_schema_with_resolved_types_stdin() {
let stdin_output = cargo::cargo_bin_cmd!("cedar")
.arg("translate-schema")
.arg("--direction")
.arg("cedar-to-json-with-resolved-types")
.write_stdin("entity User; action \"view\";")
.assert()
.code(0);
let stdin_json = std::str::from_utf8(&stdin_output.get_output().stdout)
.expect("stdin output should be decodable");
let stdin_parsed: serde_json::Value =
serde_json::from_str(stdin_json).expect("stdin output should be valid JSON");
let stdin_json_str = serde_json::to_string(&stdin_parsed).unwrap();
assert!(
!stdin_json_str.contains("EntityOrCommon"),
"Stdin output should not contain unresolved EntityOrCommon types"
);
assert!(
stdin_json_str.contains("User"),
"Stdin output should contain User entity type"
);
}
#[test]
fn test_translate_schema_with_resolved_types_invalid_input() {
let invalid_output = cargo::cargo_bin_cmd!("cedar")
.arg("translate-schema")
.arg("--direction")
.arg("cedar-to-json-with-resolved-types")
.write_stdin("invalid cedar syntax {")
.assert()
.code(1);
let stderr = std::str::from_utf8(&invalid_output.get_output().stderr)
.expect("stderr should be decodable");
assert!(
stderr.contains("error parsing schema"),
"Error message should indicate parsing failure: {}",
stderr
);
}
#[test]
fn test_translate_schema_with_resolved_types_warnings() {
let schema_with_warnings = r#"
entity String;
"#;
let output = cargo::cargo_bin_cmd!("cedar")
.arg("translate-schema")
.arg("--direction")
.arg("cedar-to-json-with-resolved-types")
.write_stdin(schema_with_warnings)
.assert()
.code(0);
let json_output =
std::str::from_utf8(&output.get_output().stdout).expect("output should be decodable");
let _parsed_json: serde_json::Value =
serde_json::from_str(json_output).expect("output should be valid JSON");
let _stderr =
std::str::from_utf8(&output.get_output().stderr).expect("stderr should be decodable");
assert!(_stderr.contains("The name `String` shadows a builtin Cedar name"));
}
#[test]
fn test_translate_schema_with_resolved_types_file_errors() {
let nonexistent_output = cargo::cargo_bin_cmd!("cedar")
.arg("translate-schema")
.arg("--direction")
.arg("cedar-to-json-with-resolved-types")
.arg("-s")
.arg("nonexistent-file.cedarschema")
.assert()
.code(1);
let stderr = std::str::from_utf8(&nonexistent_output.get_output().stderr)
.expect("stderr should be decodable");
assert!(
stderr.contains("nonexistent-file.cedarschema") || stderr.contains("No such file"),
"Error message should indicate file not found: {}",
stderr
);
}
#[test]
fn test_translate_schema_with_resolved_types_unresolvable_references() {
let unresolvable_schema = r#"
entity User = { "manager": Manager };
// Manager entity type is not defined
action "view";
"#;
let output = cargo::cargo_bin_cmd!("cedar")
.arg("translate-schema")
.arg("--direction")
.arg("cedar-to-json-with-resolved-types")
.write_stdin(unresolvable_schema)
.assert()
.code(1);
let stderr =
std::str::from_utf8(&output.get_output().stderr).expect("stderr should be decodable");
assert!(
stderr.contains("Failed to resolve schema types")
|| stderr.contains("Manager")
|| stderr.contains("resolve"),
"Error message should indicate unresolvable type reference: {}",
stderr
);
}
#[rstest]
fn visualize_entities_parses_as_dot(
#[files("sample-data/**/entities.json")]
#[files("sample-data/**/entity.json")]
path: PathBuf,
) {
let visualize = cargo::cargo_bin_cmd!("cedar")
.arg("visualize")
.arg("--entities")
.arg(path)
.assert()
.code(0);
let visualized = std::str::from_utf8(&visualize.get_output().stdout).unwrap();
graphviz_rust::parse(visualized).unwrap();
}
#[rstest]
#[case(
"sample-data/tiny_sandboxes/sample1/policy.cedar",
"sample-data/tiny_sandboxes/sample1/schema.cedarschema.json",
"sample-data/tiny_sandboxes/sample1/tests-combined.json",
CedarExitCode::Success
)]
#[case(
"sample-data/tiny_sandboxes/sample1/policy.cedar",
"sample-data/tiny_sandboxes/sample1/schema.cedarschema.json",
"sample-data/tiny_sandboxes/sample1/tests-missing-reason.json",
CedarExitCode::Failure
)]
#[case(
"sample-data/tiny_sandboxes/sample1/policy.cedar",
"sample-data/tiny_sandboxes/sample1/schema.cedarschema.json",
"sample-data/tiny_sandboxes/sample1/tests-unexpected-error.json",
CedarExitCode::Failure
)]
#[case(
"sample-data/tiny_sandboxes/sample1/policy.cedar",
"sample-data/tiny_sandboxes/sample1/schema.cedarschema.json",
"sample-data/tiny_sandboxes/sample1/tests-named.json",
CedarExitCode::Success
)]
#[case(
"sample-data/tiny_sandboxes/sample1/policy.cedar",
"sample-data/tiny_sandboxes/sample1/schema.cedarschema.json",
"sample-data/tiny_sandboxes/sample1/tests-fail.json",
CedarExitCode::Failure
)]
#[case(
"sample-data/tiny_sandboxes/sample1/policy.cedar",
"sample-data/tiny_sandboxes/sample1/schema.cedarschema.json",
"sample-data/tiny_sandboxes/sample1/tests-format-error.json",
CedarExitCode::Failure
)]
#[case(
"sample-data/tiny_sandboxes/sample1/policy.cedar",
"sample-data/tiny_sandboxes/sample1/schema.cedarschema.json",
"sample-data/tiny_sandboxes/sample1/tests-format-error2.json",
CedarExitCode::Failure
)]
#[case(
"sample-data/tiny_sandboxes/sample1/policy.cedar",
"sample-data/tiny_sandboxes/sample1/schema.cedarschema.json",
"sample-data/tiny_sandboxes/sample1/no-such-file.json",
CedarExitCode::Failure
)]
#[case(
"sample-data/tiny_sandboxes/sample2/policy.cedar",
"sample-data/tiny_sandboxes/sample2/schema.cedarschema.json",
"sample-data/tiny_sandboxes/sample2/tests-combined.json",
CedarExitCode::Success
)]
#[case(
"sample-data/tiny_sandboxes/sample3/policy.cedar",
"sample-data/tiny_sandboxes/sample3/schema.cedarschema.json",
"sample-data/tiny_sandboxes/sample3/tests-combined.json",
CedarExitCode::Success
)]
#[case(
"sample-data/tiny_sandboxes/sample4/policy.cedar",
"sample-data/tiny_sandboxes/sample4/schema.cedarschema.json",
"sample-data/tiny_sandboxes/sample4/tests-combined.json",
CedarExitCode::Success
)]
#[case(
"sample-data/tiny_sandboxes/sample6/policy.cedar",
"sample-data/tiny_sandboxes/sample6/schema.cedarschema.json",
"sample-data/tiny_sandboxes/sample6/tests-combined.json",
CedarExitCode::Success
)]
#[case(
"sample-data/tiny_sandboxes/sample7/policy.cedar",
"sample-data/tiny_sandboxes/sample7/schema.cedarschema.json",
"sample-data/tiny_sandboxes/sample7/tests-combined.json",
CedarExitCode::Success
)]
#[case(
"sample-data/tiny_sandboxes/sample9/policy.cedar",
"sample-data/tiny_sandboxes/sample9/schema.cedarschema.json",
"sample-data/tiny_sandboxes/sample9/tests-combined.json",
CedarExitCode::Success
)]
#[case(
"sample-data/tiny_sandboxes/sample10/policy.cedar",
"sample-data/tiny_sandboxes/sample10/schema.cedarschema",
"sample-data/tiny_sandboxes/sample10/tests-error.json",
CedarExitCode::Failure
)]
#[case(
"sample-data/tiny_sandboxes/sample11/valid_policy.cedar",
"sample-data/tiny_sandboxes/sample11/schema.cedarschema.json",
"sample-data/tiny_sandboxes/sample11/test-schema-error.json",
CedarExitCode::Failure
)]
#[case(
"sample-data/tiny_sandboxes/sample11/invalid_policy.cedar",
"sample-data/tiny_sandboxes/sample11/schema.cedarschema.json",
"sample-data/tiny_sandboxes/sample11/test-policy-error.json",
CedarExitCode::Failure
)]
#[track_caller]
fn test_run_tests_samples(
#[case] policies_file: impl Into<String>,
#[case] schema_file: impl Into<PathBuf>,
#[case] test_file: impl Into<String>,
#[case] exit_code: CedarExitCode,
) {
let policies_file = policies_file.into();
let test_file = test_file.into();
let cmd = RunTestsArgs {
policies: PoliciesArgs {
policies_file: Some(policies_file),
policy_format: PolicyFormat::Cedar,
template_linked_file: None,
},
tests: test_file,
schema: OptionalSchemaArgs {
schema_file: Some(schema_file.into()),
schema_format: SchemaFormat::Json,
},
};
let output = run_tests(&cmd);
assert_eq!(exit_code, output, "{cmd:#?}")
}
#[test]
#[cfg(feature = "tpe")]
fn test_tpe() {
let policies: &str = "sample-data/tpe_rfc/policies.cedar";
let entities: &str = "sample-data/tpe_rfc/entities.json";
let schema: &str = "sample-data/tpe_rfc/schema.cedarschema";
let request_json_file: &str = "sample-data/tpe_rfc/request.json";
let context_file: &str = "sample-data/tpe_rfc/context.json";
cargo::cargo_bin_cmd!("cedar")
.arg("tpe")
.arg("--principal-type")
.arg("User")
.arg("--principal-eid")
.arg("Alice")
.arg("-a")
.arg(r#"Action::"View""#)
.arg("--resource-type")
.arg("Document")
.arg("-p")
.arg(policies)
.arg("--entities")
.arg(entities)
.arg("-s")
.arg(schema)
.assert()
.code(0);
cargo::cargo_bin_cmd!("cedar")
.arg("tpe")
.arg("--principal-type")
.arg("User")
.arg("--principal-eid")
.arg("Alice")
.arg("-a")
.arg(r#"Action::"Delete""#)
.arg("--resource-type")
.arg("Document")
.arg("-p")
.arg(policies)
.arg("--entities")
.arg(entities)
.arg("-s")
.arg(schema)
.arg("--context")
.arg(context_file)
.assert()
.code(2);
cargo::cargo_bin_cmd!("cedar")
.arg("tpe")
.arg("--request-json")
.arg(request_json_file)
.arg("-p")
.arg(policies)
.arg("--entities")
.arg(entities)
.arg("-s")
.arg(schema)
.assert()
.code(0);
}
#[rstest]
#[case("principal")]
#[case("1 + 1")]
fn check_parse_expr_ok(#[case] expr: &str) {
cargo::cargo_bin_cmd!("cedar")
.arg("check-parse")
.arg("--expression")
.arg(expr)
.assert()
.code(0);
}
#[rstest]
#[case("")]
#[case("1+foo")]
fn check_parse_expr_err(#[case] expr: &str) {
cargo::cargo_bin_cmd!("cedar")
.arg("check-parse")
.arg("--expression")
.arg(expr)
.assert()
.code(1);
}