Skip to content

Commit c879c22

Browse files
committed
fix 437, properly handle unknowns in the context.
Signed-off-by: Mohamed Amine Ouali <mdamine@amazon.com>
1 parent 197763e commit c879c22

1 file changed

Lines changed: 191 additions & 0 deletions

File tree

cedar-policy-validator/src/types.rs

Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -552,6 +552,9 @@ impl Type {
552552
restricted_expr: BorrowedRestrictedExpr<'_>,
553553
extensions: &Extensions<'_>,
554554
) -> Result<bool, ExtensionFunctionLookupError> {
555+
if restricted_expr.as_unknown().is_some() {
556+
return Ok(true);
557+
}
555558
match self {
556559
Type::Never => Ok(false), // no expr has type Never
557560
Type::Primitive {
@@ -1742,6 +1745,7 @@ pub enum Primitive {
17421745
mod test {
17431746
use super::*;
17441747
use crate::{json_schema, ActionBehavior};
1748+
use cedar_policy_core::ast::Context;
17451749
use cool_asserts::assert_matches;
17461750

17471751
impl Type {
@@ -2520,6 +2524,193 @@ mod test {
25202524
.expect("Expected valid schema")
25212525
}
25222526

2527+
#[test]
2528+
#[cfg(feature = "partial-eval")]
2529+
fn test_typecheck_partial_value_with_unknown() {
2530+
let context = Context::from_json_value(serde_json::json!({
2531+
"a": {
2532+
"__extn": {
2533+
"fn": "unknown",
2534+
"arg": "test_arg"
2535+
}
2536+
},
2537+
}))
2538+
.unwrap();
2539+
2540+
let typeValidator = Type::record_with_attributes(
2541+
[
2542+
(
2543+
"a".into(),
2544+
AttributeType::optional_attribute(Type::primitive_boolean()),
2545+
),
2546+
(
2547+
"b".into(),
2548+
AttributeType::optional_attribute(Type::primitive_boolean()),
2549+
),
2550+
(
2551+
"c".into(),
2552+
AttributeType::optional_attribute(Type::primitive_boolean()),
2553+
),
2554+
],
2555+
OpenTag::ClosedAttributes,
2556+
);
2557+
2558+
let result = typeValidator
2559+
.typecheck_partial_value(&context.clone().into(), Extensions::all_available());
2560+
assert_eq!(result.unwrap(), true);
2561+
}
2562+
2563+
#[test]
2564+
#[cfg(feature = "partial-eval")]
2565+
fn test_typecheck_partial_value_with_embedded_unknown() {
2566+
let context = Context::from_json_value(serde_json::json!({
2567+
"a": {
2568+
"b":{
2569+
"__extn": {
2570+
"fn": "unknown",
2571+
"arg": "test_arg"
2572+
}
2573+
}
2574+
},
2575+
}))
2576+
.unwrap();
2577+
2578+
let embedded_attributes = Type::record_with_attributes(
2579+
[
2580+
(
2581+
"b".into(),
2582+
AttributeType::optional_attribute(Type::primitive_boolean()),
2583+
),
2584+
(
2585+
"c".into(),
2586+
AttributeType::optional_attribute(Type::primitive_boolean()),
2587+
),
2588+
],
2589+
OpenTag::ClosedAttributes,
2590+
);
2591+
2592+
let typeValidator = Type::record_with_attributes(
2593+
[(
2594+
"a".into(),
2595+
AttributeType::optional_attribute(embedded_attributes),
2596+
)],
2597+
OpenTag::ClosedAttributes,
2598+
);
2599+
2600+
let result = typeValidator
2601+
.typecheck_partial_value(&context.clone().into(), Extensions::all_available());
2602+
2603+
// c is optional attribute it is not required to provide it.
2604+
assert_eq!(result.unwrap(), true);
2605+
}
2606+
2607+
#[test]
2608+
#[cfg(feature = "partial-eval")]
2609+
fn test_typecheck_partial_value_with_unknown1() {
2610+
let context = Context::from_json_value(serde_json::json!({
2611+
"foo": 1,
2612+
"bar": {
2613+
"__extn": {
2614+
"fn": "unknown",
2615+
"arg": "test_arg"
2616+
}
2617+
},
2618+
}))
2619+
.unwrap();
2620+
2621+
let typeValidator = Type::record_with_attributes(
2622+
[
2623+
(
2624+
"foo".into(),
2625+
AttributeType::required_attribute(Type::primitive_long()),
2626+
),
2627+
(
2628+
"bar".into(),
2629+
AttributeType::required_attribute(Type::primitive_string()),
2630+
),
2631+
],
2632+
OpenTag::ClosedAttributes,
2633+
);
2634+
2635+
let result = typeValidator
2636+
.typecheck_partial_value(&context.clone().into(), Extensions::all_available());
2637+
//success both foo and bar are provided
2638+
assert_eq!(result.unwrap(), true);
2639+
}
2640+
2641+
#[test]
2642+
#[cfg(feature = "partial-eval")]
2643+
fn test_typecheck_partial_value_with_unknown2() {
2644+
let context = Context::from_json_value(serde_json::json!({
2645+
"bar": {
2646+
"__extn": {
2647+
"fn": "unknown",
2648+
"arg": "test_arg"
2649+
}
2650+
},
2651+
"foo": 1,
2652+
}))
2653+
.unwrap();
2654+
2655+
let typeValidator = Type::record_with_attributes(
2656+
[
2657+
(
2658+
"foo".into(),
2659+
AttributeType::required_attribute(Type::primitive_string()),
2660+
),
2661+
(
2662+
"bar".into(),
2663+
AttributeType::required_attribute(Type::primitive_string()),
2664+
),
2665+
],
2666+
OpenTag::ClosedAttributes,
2667+
);
2668+
2669+
let result = typeValidator
2670+
.typecheck_partial_value(&context.clone().into(), Extensions::all_available());
2671+
//fail foo is string in schema not long
2672+
assert_eq!(result.unwrap(), false);
2673+
}
2674+
2675+
#[test]
2676+
#[cfg(feature = "partial-eval")]
2677+
fn test_typecheck_partial_value_with_unknown3() {
2678+
let context = Context::from_json_value(serde_json::json!({
2679+
"bar": {
2680+
"__extn": {
2681+
"fn": "unknown",
2682+
"arg": "test_arg"
2683+
}
2684+
},
2685+
"foo": 1,
2686+
}))
2687+
.unwrap();
2688+
2689+
let typeValidator = Type::record_with_attributes(
2690+
[
2691+
(
2692+
"foo".into(),
2693+
AttributeType::required_attribute(Type::primitive_long()),
2694+
),
2695+
(
2696+
"bar".into(),
2697+
AttributeType::required_attribute(Type::primitive_string()),
2698+
),
2699+
(
2700+
"baz".into(),
2701+
AttributeType::required_attribute(Type::primitive_string()),
2702+
),
2703+
],
2704+
OpenTag::ClosedAttributes,
2705+
);
2706+
2707+
let result = typeValidator
2708+
.typecheck_partial_value(&context.clone().into(), Extensions::all_available());
2709+
2710+
//fail baz is required in the schema
2711+
assert_eq!(result.unwrap(), false);
2712+
}
2713+
25232714
/// Test cases with entity type Action are interesting because Action
25242715
/// does not need to be declared in the entity type list.
25252716
#[test]

0 commit comments

Comments
 (0)