diff options
| author | Jakob L. Kreuze | 2023-12-19 13:52:25 -0500 |
|---|---|---|
| committer | Jakob L. Kreuze | 2023-12-19 13:52:25 -0500 |
| commit | 14b2cf6a158b840194177973bb9fd0067cbb35b9 (patch) | |
| tree | 5a5abc6f98d87ac04fce1e97c84f59bb0e21d7f2 | |
| parent | d96710a823d7f9ede16a18774131a47729e967a0 (diff) | |
Initial check-in of XACML implementation in Rego
| -rw-r--r-- | xacml-translation/xacml.rego | 726 |
1 files changed, 726 insertions, 0 deletions
diff --git a/xacml-translation/xacml.rego b/xacml-translation/xacml.rego new file mode 100644 index 0000000..b5ba0ff --- /dev/null +++ b/xacml-translation/xacml.rego @@ -0,0 +1,726 @@ +package equivalence + +import future.keywords.every +import future.keywords.if +import future.keywords.in + +######################################################################## +# Data Types +######################################################################## + +## MatchResult + +# - is_match => { "match_result": true } +# - no_match => { "match_result": false } +# - indeterminate => { "match_result": "indeterminate" } + +## Decision + +# - permit => { "decision": "permit" } +# - deny => { "decision": "deny" } +# - not_applicable => { "decision": "not_applicable" } +# - indeterminate => { "decision": "indeterminate" } + +## Extended Decision + +# - permit => { "decision_extended": "permit" } +# - deny => { "decision_extended": "deny" } +# - not_applicable => { "decision_extended": "not_applicable" } +# - indeterminate => { "decision_extended": "indeterminate" } +# - indeterminate_d => { "decision_extended": "indeterminate_d" } +# - indeterminate_p => { "decision_extended": "indeterminate_p" } +# - indeterminate_dp => { "decision_extended": "indeterminate_dp" } + +lift_decision_indeterminate({ "decision": "not_applicable" }) := { "decision": "not_applicable" } +lift_decision_indeterminate({ "decision": "permit" }) := { "decision": "indeterminate_p" } +lift_decision_indeterminate({ "decision": "deny" }) := { "decision": "indeterminate_d" } +lift_decision_indeterminate({ "decision": "indeterminate" }) := { "decision": "indeterminate_dp" } +lift_decision_indeterminate({ "decision": "indeterminate_dp" }) := { "decision": "indeterminate_dp" } +lift_decision_indeterminate({ "decision": "indeterminate_p" }) := { "decision": "indeterminate_p" } +lift_decision_indeterminate({ "decision": "indeterminate_d" }) := { "decision": "indeterminate_d" } + +## Value + +# - { "kind": "primitive", +# "type": string, +# "value": string } +# - { "kind": "bag", +# "values": ... } + +### Booleans + +true_value := { "kind": "primitive", "type": "boolean", "value": true } +false_value := { "kind": "primitive", "type": "boolean", "value": false } +indeterminate_value := { "kind": "primitive", "type": "boolean" } + +is_indeterminate(value) if { is_null(value.value) } + +## StatusCode + +# - ok => { "status": "ok" } +# - missing_attribute => { "status": "missing_attribute" } +# - syntax_error => { "status": "syntax_error" } +# - processing_error => { "status": "processing_error" } + +## AttributeDesignator + +# - { category : string +# identifier : string +# type : string +# issuer : string or null +# must_be_present : boolean } + +## Expression + +# - { "expression": "apply", +# "function": string, +# "args": [string, ...] } +# - { "expression": "attribute_designator", +# "inner": AttributeDesignator } +# - { "expression": "attribute_value", +# "inner": Value } +# - { "expression": "function" +# "function": string } + +## Match + +# - { "function": string, +# "designator": AttributeDesignator, +# "value": Value } + +## Obligation + +# - { "assignments": [Attribute, ...], +# "identifier": string } + +## ObligationExpression + +# - { "assignments": [AttributeAssignmentExpression, ...], +# "identifier": string, +# "fulfill_on": Decision } + +## Advice + +# - { "assignments": [Attribute, ...], +# "identifier": string } + +## AdviceExpression + +# - { "assignments": [AttributeAssignmentExpression, ...], +# "identifier": string, +# "applies_to": Decision } + +## AttributeAssignmentExpression + +# - { "category": string, +# "identifier": string, +# "issuer": string or null, +# "expression": Expression } + +## Target: [[[Expression, ...], ...], ...] + +## Rule + +# - { "target": Target, +# "condition": Expression or null, +# "effect": "permit" or "deny", +# "obligations": [ObligationExpression, ...], +# "advice": [AdviceExpression, ...] } + +## Policy + +# - { "combinator": string, +# "target": Target, +# "obligations": [ObligationExpression, ...], +# "advice": [AdviceExpression, ...] } + +## PolicySet + +# - { "combinator": string, +# "target": Target, +# "obligations": [ObligationExpression, ...], +# "advice": [AdviceExpression, ...] } + +# We assume the request attributes are stored in `input.request` as an array or set of +# +# { category : string +# identifier : string +# issuer : string or null +# value : [Value, ...] } + +######################################################################## +# Match Functions +######################################################################## + +## TODO +apply_xacml_function("urn:oasis:names:tc:xacml:1.0:function:string-equal", [("http://www.w3.org/2001/XMLSchema#string", a), ("http://www.w3.org/2001/XMLSchema#string", b)]) := true_value if { + a == b +} else := false_value + +######################################################################## +# AttributeDesignator +######################################################################## + +designator_matches(designator, attribute) if { + attribute.category == designator.category + attribute.identifier == designator.identifier + attribute.value.type == designator.type + attribute.attr.issuer == null +} + +designator_matches(designator, attribute) if { + attribute.category == designator.category + attribute.identifier == designator.identifier + attribute.value.type == designator.type + attribute.attr.issuer == designator.issuer +} + +evaluate_designator(designator) := result if { + xs := [y.value | y := input.request[_]; designator_matches(designator, y)] + count(xs) > 0 + result := { "kind": "bag", "values": xs } +} + +evaluate_designator(designator) := result if { + xs := [y.value | y := input.request[_]; designator_matches(designator, y)] + count(xs) == 0 + not designator.must_be_present + result := { "kind": "bag", "values": xs } +} + +evaluate_designator(designator) := { "status": "missing_attribute" } if { + xs := [y.value | y := input.request[_]; designator_matches(designator, y)] + count(xs) == 0 + designator.must_be_present +} + +######################################################################### +# Match +######################################################################## + +evaluate_match(match) := { "match_result": true_value } if { + designator_result := evaluate_designator(match.designator) + + # Designator evaluates without error. + is_array(designator_result) + + some x in designator_result + apply_xacml_function(match.fn, x).value == true +} else := { "match_result": indeterminate_value } if { + designator_result := evaluate_designator(match.designator) + + # Designator evaluates without error. + is_array(designator_result) + + some x in designator_result + is_indeterminate(apply_xacml_function(match.fn, x)) +} else := { "match_result": false_value } if { + designator_result := evaluate_designator(match.designator) + + # Designator evaluates without error. + is_array(designator_result) +} else := { "match_result": indeterminate_value } + +# Last case runs when evaluating the designator results in an error. + +evaluate_all_of(conj) := { "match_result": true_value } if { + every x in conj { + evaluate_match(x) == true + } +} else := { "match_result": "indeterminate" } if { + some x in conj + is_indeterminate(evaluate_match(x).match_result) +} else := { "match_result": "no_match" } + +evaluate_any_of([]) := { "match_result": true_value } +evaluate_any_of(disj) := { "match_result": true_value } if { + some x in disj + evaluate_all_of(x) == { "match_result": true_value } +} else := { "match_result": "indeterminate" } if { + some x in disj + evaluate_all_of(x) == { "match_result": true_value } +} else := { "match_result": "no_match" } + + +######################################################################## +# Target +######################################################################## + +evaluate_target([]) := { "match_result": true_value } +evaluate_target(xs) := { "match_result": true_value } if { + every disj in xs { + evaluate_any_of(disj).match_result.value == true + } +} else := { "match_result": false_value } if { + some disj in xs + evaluate_any_of(disj).match_result.value == false +} else := { "match_result": indeterminate_value } + +######################################################################## +# Expression +######################################################################## + +evaluate_expression({ "expression": "apply", "function": function_name, "args": args }) := x if { + x := apply_xacml_function(function_name, args) +} +evaluate_expression({ "expression": "attribute_designator", "inner": designator }) := x if { + x := evaluate_designator(designator) +} +evaluate_expression({ "expression": "attribute_value", "inner": value }) := x if { + x := value +} +evaluate_expression({ "expression": "function", "function": name }) := x if { + x := name +} + +######################################################################## +# Obligations and Advice +######################################################################## + +evaluate_attribute_assignment_expression(expr) := assignment { + { "kind": "primitive", "value": inner } = evaluate_expression(expr.expression) + assignment := { "category": expr.category, + "identifier": expr.identifier, + "issuer": expr.issuer, + "value": inner } +} + +evaluate_obligation_expression(obligation_expression) := obligation { + assignments := [evaluate_attribute_assignment_expression(expr) | expr := obligation_expression.assignments[_]] + obligation := { "assignments": assignments, "identifier": obligation_expression.identifier } +} + +evaluate_advice_expression(advice_expression) := advice { + assignments := [evaluate_attribute_assignment_expression(expr) | expr := advice_expression.assignments[_]] + advice := { "assignments": assignments, "identifier": advice_expression.identifier } +} + + +######################################################################## +# Rule +######################################################################## + +# Condition is specified and applicable +evaluate_rule_decision(rule) := { "decision_extended": decision } { + evaluate_target(rule.target).match_result.value == true + + is_object(rule.condition) + evaluate_expression(rule.condition) == true + + decision := rule.effect +} +# Condition is specified and not applicable +evaluate_rule_decision(rule) := { "decision_extended": "not_applicable" } { + evaluate_target(rule.target).match_result.value == true + evaluate_expression(rule.condition) == false +} +# Condition is indeterminate +evaluate_rule_decision(rule) := { "decision_extended": "indeterminate_p" } { + evaluate_target(rule.target).match_result.value == true + condition := evaluate_expression(rule.condition) + is_null(condition) + rule.effect == "permit" +} +evaluate_rule_decision(rule) := { "decision_extended": "indeterminate_d" } { + evaluate_target(rule.target).match_result.value == true + condition := evaluate_expression(rule.condition) + is_null(condition) + rule.effect == "deny" +} +# Condition is unspecified +evaluate_rule_decision(rule) := { "decision_extended": decision } { + evaluate_target(rule.target).match_result.value == true + decision := rule.effect +} + +evaluate_rule_decision(rule) := { "decision_extended": "not_applicable" } { + evaluate_target(rule.target).match_result.value == false +} +evaluate_rule_decision(rule) := { "decision_extended": "indeterminate_p" } { + is_indeterminate(evaluate_target(rule.target)) + rule.effect == "permit" +} +evaluate_rule_decision(rule) := { "decision_extended": "indeterminate_d" } { + is_indeterminate(evaluate_target(rule.target)) + rule.effect == "permit" +} + +evaluate_rule_advices(rule) := { "advice": advice } if { + decision := evaluate_rule_decision(rule) + advice := [expr | expr := rule.advice[_]; expr.applies_to == decision ] +} + +evaluate_rule_obligations(rule) := { "obligations": obligations } if { + decision := evaluate_rule_decision(rule) + obligations := [expr | expr := rule.obligations[_]; expr.fulfill_on == decision ] +} + +######################################################################## +# Policy +######################################################################## + +evaluate_rule_combinator("deny_overrides", results) := { "decision_extended": "deny" } if { + some result in results + result.decision_extended == "deny" +} else := { "decision_extended": "indeterminate_dp" } if { + some result in results + result.decision_extended == "indeterminate_dp" +} else := { "decision_extended": "indeterminate_dp" } if { + some result1 in results + some result2 in results + result1.decision_extended == "indeterminate_d" + result1.decision_extended == "indeterminate_p" +} else := { "decision_extended": "indeterminate_d" } if { + some result in results + result.decision_extended == "indeterminate_d" +} else := { "decision_extended": "permit" } if { + some result in results + result.decision_extended == "permit" +} else := { "decision_extended": "indeterminate_p" } if { + some result in results + result.decision_extended == "indeterminate_p" +} else := { "decision_extended": "not_applicable" } + +evaluate_rule_combinator("ordered_deny_overrides", results) := { "decision_extended": "deny" } if { + some result in results + result.decision_extended == "deny" +} else := { "decision_extended": "indeterminate_dp" } if { + some result in results + result.decision_extended == "indeterminate_dp" +} else := { "decision_extended": "indeterminate_dp" } if { + some result1 in results + some result2 in results + result1.decision_extended == "indeterminate_d" + result1.decision_extended == "indeterminate_p" +} else := { "decision_extended": "indeterminate_d" } if { + some result in results + result.decision_extended == "indeterminate_d" +} else := { "decision_extended": "permit" } if { + some result in results + result.decision_extended == "permit" +} else := { "decision_extended": "indeterminate_p" } if { + some result in results + result.decision_extended == "indeterminate_p" +} else := { "decision_extended": "not_applicable" } + +evaluate_rule_combinator("permit_overrides", results) := { "decision_extended": "permit" } if { + some result in results + result.decision_extended == "permit" +} else := { "decision_extended": "indeterminate_dp" } if { + some result in results + result.decision_extended == "indeterminate_dp" +} else := { "decision_extended": "indeterminate_dp" } if { + some result1 in results + some result2 in results + result1.decision_extended == "indeterminate_d" + result1.decision_extended == "indeterminate_p" +} else := { "decision_extended": "indeterminate_p" } if { + some result in results + result.decision_extended == "indeterminate_p" +} else := { "decision_extended": "deny" } if { + some result in results + result.decision_extended == "deny" +} else := { "decision_extended": "indeterminate_d" } if { + some result in results + result.decision_extended == "indeterminate_d" +} else := { "decision_extended": "not_applicable" } + +evaluate_rule_combinator("ordered_permit_overrides", results) := { "decision_extended": "permit" } if { + some result in results + result.decision_extended == "permit" +} else := { "decision_extended": "indeterminate_dp" } if { + some result in results + result.decision_extended == "indeterminate_dp" +} else := { "decision_extended": "indeterminate_dp" } if { + some result1 in results + some result2 in results + result1.decision_extended == "indeterminate_d" + result1.decision_extended == "indeterminate_p" +} else := { "decision_extended": "indeterminate_p" } if { + some result in results + result.decision_extended == "indeterminate_p" +} else := { "decision_extended": "deny" } if { + some result in results + result.decision_extended == "deny" +} else := { "decision_extended": "indeterminate_d" } if { + some result in results + result.decision_extended == "indeterminate_d" +} else := { "decision_extended": "not_applicable" } + +evaluate_rule_combinator("deny_unless_permit", results) := { "decision_extended": "permit" } if { + some result in results + result.decision_extended == "permit" +} else := { "decision_extended": "deny" } + +evaluate_rule_combinator("permit_unless_deny", results) := { "decision_extended": "deny" } if { + some result in results + result.decision_extended == "deny" +} else := { "decision_extended": "permit" } + +evaluate_rule_combinator("first_applicable", results) := result if { + indices := [i | results[i].decision_extended != "not_applicable"] + count(indices) > 0 + result := results[max(indices)] + result.decision_extended == "deny" +} else := { "decision_extended": "not_applicable" } + +evaluate_rule_combinator("legacy_deny_overrides", results) := { "decision_extended": "deny" } if { + some result in results + result.decision_extended == "deny" +} else := { "decision_extended": "indeterminate" } if { + some result in results + result.decision_extended == "indeterminate_d" +} else := { "decision_extended": "permit" } if { + some result in results + result.decision_extended == "permit" +} else := { "decision_extended": "indeterminate" } if { + some result in results + result.decision_extended == "indeterminate_p" +} else := { "decision_extended": "not_applicable" } + +evaluate_rule_combinator("ordered_legacy_deny_overrides", results) := { "decision_extended": "deny" } if { + some result in results + result.decision_extended == "deny" +} else := { "decision_extended": "indeterminate" } if { + some result in results + result.decision_extended == "indeterminate_d" +} else := { "decision_extended": "permit" } if { + some result in results + result.decision_extended == "permit" +} else := { "decision_extended": "indeterminate" } if { + some result in results + result.decision_extended == "indeterminate_p" +} else := { "decision_extended": "not_applicable" } + +evaluate_rule_combinator("legacy_permit_overrides", results) := { "decision_extended": "permit" } if { + some result in results + result.decision_extended == "permit" +} else := { "decision_extended": "indeterminate" } if { + some result in results + result.decision_extended == "indeterminate_p" +} else := { "decision_extended": "deny" } if { + some result in results + result.decision_extended == "deny" +} else := { "decision_extended": "indeterminate" } if { + some result in results + result.decision_extended == "indeterminate_d" +} else := { "decision_extended": "not_applicable" } + +evaluate_rule_combinator("ordered_legacy_permit_overrides", results) := { "decision_extended": "permit" } if { + some result in results + result.decision_extended == "permit" +} else := { "decision_extended": "indeterminate" } if { + some result in results + result.decision_extended == "indeterminate_p" +} else := { "decision_extended": "deny" } if { + some result in results + result.decision_extended == "deny" +} else := { "decision_extended": "indeterminate" } if { + some result in results + result.decision_extended == "indeterminate_d" +} else := { "decision_extended": "not_applicable" } + +# child_results := [result | rule := policy.rules[_]; result := evaluate_rule_decision(rule)] +evaluate_policy_decision(policy, child_results) := decision if { + evaluate_target(policy.target).match_result.value == true + decision := evaluate_rule_combinator(policy.combinator, child_results) +} else := decision if { + is_indeterminate(evaluate_target(policy.target)) + decision := lift_decision_indeterminate(evaluate_rule_combinator(policy.combinator, child_results)) +} else := { "decision_extended": "not_applicable" } + +# children_advice := [advice | rule := policy.rules[_]; expr := evaluate_rule_advices(rule); advice := expr[_]] +evaluate_policy_advices(policy, child_results, children_advice) := { "advice" : advice } if { + decision := evaluate_policy_decision(policy, child_results) + policy_advice := [expr | expr := policy.advice[_]; expr.applies_to == decision ] + advice := array.concat(policy_advice, children_advice) +} + +# children_obligations := [obligation | rule := policy.rules[_]; expr := evaluate_rule_obligations(rule); obligation := expr[_]] +evaluate_policy_obligations(policy, child_results, children_obligations) := { "obligations" : obligations } if { + decision := evaluate_policy_decision(policy, child_results) + policy_obligations := [expr | expr := policy.obligations[_]; expr.applies_to == decision ] + obligations := array.concat(policy_obligations, children_obligations) +} + +######################################################################## +# PolicySet +######################################################################## + +evaluate_policy_combinator("deny_overrides", results) := { "decision_extended": "deny" } if { + some result in results + result.decision_extended == "deny" +} else := { "decision_extended": "indeterminate_dp" } if { + some result in results + result.decision_extended == "indeterminate_dp" +} else := { "decision_extended": "indeterminate_dp" } if { + some result1 in results + some result2 in results + result1.decision_extended == "indeterminate_d" + result1.decision_extended == "indeterminate_p" +} else := { "decision_extended": "indeterminate_d" } if { + some result in results + result.decision_extended == "indeterminate_d" +} else := { "decision_extended": "permit" } if { + some result in results + result.decision_extended == "permit" +} else := { "decision_extended": "indeterminate_p" } if { + some result in results + result.decision_extended == "indeterminate_p" +} else := { "decision_extended": "not_applicable" } + +evaluate_policy_combinator("ordered_deny_overrides", results) := { "decision_extended": "deny" } if { + some result in results + result.decision_extended == "deny" +} else := { "decision_extended": "indeterminate_dp" } if { + some result in results + result.decision_extended == "indeterminate_dp" +} else := { "decision_extended": "indeterminate_dp" } if { + some result1 in results + some result2 in results + result1.decision_extended == "indeterminate_d" + result1.decision_extended == "indeterminate_p" +} else := { "decision_extended": "indeterminate_d" } if { + some result in results + result.decision_extended == "indeterminate_d" +} else := { "decision_extended": "permit" } if { + some result in results + result.decision_extended == "permit" +} else := { "decision_extended": "indeterminate_p" } if { + some result in results + result.decision_extended == "indeterminate_p" +} else := { "decision_extended": "not_applicable" } + +evaluate_policy_combinator("permit_overrides", results) := { "decision_extended": "permit" } if { + some result in results + result.decision_extended == "permit" +} else := { "decision_extended": "indeterminate_dp" } if { + some result in results + result.decision_extended == "indeterminate_dp" +} else := { "decision_extended": "indeterminate_dp" } if { + some result1 in results + some result2 in results + result1.decision_extended == "indeterminate_d" + result1.decision_extended == "indeterminate_p" +} else := { "decision_extended": "indeterminate_p" } if { + some result in results + result.decision_extended == "indeterminate_p" +} else := { "decision_extended": "deny" } if { + some result in results + result.decision_extended == "deny" +} else := { "decision_extended": "indeterminate_d" } if { + some result in results + result.decision_extended == "indeterminate_d" +} else := { "decision_extended": "not_applicable" } + +evaluate_policy_combinator("ordered_permit_overrides", results) := { "decision_extended": "permit" } if { + some result in results + result.decision_extended == "permit" +} else := { "decision_extended": "indeterminate_dp" } if { + some result in results + result.decision_extended == "indeterminate_dp" +} else := { "decision_extended": "indeterminate_dp" } if { + some result1 in results + some result2 in results + result1.decision_extended == "indeterminate_d" + result1.decision_extended == "indeterminate_p" +} else := { "decision_extended": "indeterminate_p" } if { + some result in results + result.decision_extended == "indeterminate_p" +} else := { "decision_extended": "deny" } if { + some result in results + result.decision_extended == "deny" +} else := { "decision_extended": "indeterminate_d" } if { + some result in results + result.decision_extended == "indeterminate_d" +} else := { "decision_extended": "not_applicable" } + +evaluate_policy_combinator("deny_unless_permit", results) := { "decision_extended": "permit" } if { + some result in results + result.decision_extended == "permit" +} else := { "decision_extended": "deny" } + +evaluate_policy_combinator("permit_unless_deny", results) := { "decision_extended": "deny" } if { + some result in results + result.decision_extended == "deny" +} else := { "decision_extended": "permit" } + +evaluate_policy_combinator("first_applicable", results) := result if { + indices := [i | results[i].decision_extended != "not_applicable"] + count(indices) > 0 + result := results[max(indices)] + result.decision_extended == "deny" +} else := { "decision_extended": "not_applicable" } + +evaluate_policy_combinator("only_one_applicable", results) := result if { + applicable := [result | result := results[i]; result.decision_extended != "not_applicable"] + count(applicable) == 1 + result := applicable[0] +} else := { "decision_extended": "not_applicable" } + +evaluate_policy_combinator("legacy_deny_overrides", results) := { "decision_extended": "deny" } if { + some result in results + result.decision_extended == "deny" +} else := { "decision_extended": "deny" } if { + some result in results + result.decision_extended == "indeterminate" +} else := { "decision_extended": "permit" } if { + some result in results + result.decision_extended == "permit" +} else := { "decision_extended": "not_applicable" } + +evaluate_policy_combinator("ordered_legacy_deny_overrides", results) := { "decision_extended": "deny" } if { + some result in results + result.decision_extended == "deny" +} else := { "decision_extended": "deny" } if { + some result in results + result.decision_extended == "indeterminate" +} else := { "decision_extended": "permit" } if { + some result in results + result.decision_extended == "permit" +} else := { "decision_extended": "not_applicable" } + +evaluate_policy_combinator("legacy_permit_overrides", results) := { "decision_extended": "permit" } if { + some result in results + result.decision_extended == "permit" +} else := { "decision_extended": "deny" } if { + some result in results + result.decision_extended == "deny" +} else := { "decision_extended": "indeterminate" } if { + some result in results + result.decision_extended == "indeterminate" +} else := { "decision_extended": "not_applicable" } + +evaluate_policy_combinator("ordered_legacy_permit_overrides", results) := { "decision_extended": "permit" } if { + some result in results + result.decision_extended == "permit" +} else := { "decision_extended": "indeterminate" } if { + some result in results + result.decision_extended == "indeterminate_p" +} else := { "decision_extended": "deny" } if { + some result in results + result.decision_extended == "deny" +} else := { "decision_extended": "indeterminate" } if { + some result in results + result.decision_extended == "indeterminate_d" +} else := { "decision_extended": "not_applicable" } + +evaluate_policyset_decision(policyset, child_results) := decision if { + evaluate_target(policyset.target).match_result.value == true + decision := evaluate_policy_combinator(policyset.combinator, child_results) +} else := decision if { + is_indeterminate(evaluate_target(policyset.target)) + decision := lift_decision_indeterminate(evaluate_policy_combinator(policyset.combinator, child_results)) +} else := { "decision_extended": "not_applicable" } + +evaluate_policyset_advices(policyset, child_results, child_advice) := { "advice" : advice } if { + decision := evaluate_policyset_decision(policyset, child_results) + policyset_advice := [expr | expr := policyset.advice[_]; expr.applies_to == decision ] + advice := array.concat(policyset_advice, child_advice) +} + +evaluate_policyset_obligations(policyset, child_results, child_obligations) := { "obligations" : obligations } if { + decision := evaluate_policyset_decision(policyset, child_results) + policyset_obligations := [expr | expr := policyset.obligations[_]; expr.applies_to == decision ] + obligations := array.concat(policyset_obligations, child_obligations) +} |