Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Full Evaluation Option for Policy Expressions. #1445

Open
1 of 2 tasks
amzn-mdamine opened this issue Jan 27, 2025 · 1 comment
Open
1 of 2 tasks

Full Evaluation Option for Policy Expressions. #1445

amzn-mdamine opened this issue Jan 27, 2025 · 1 comment
Labels
feature-request This issue requets a substantial new feature

Comments

@amzn-mdamine
Copy link

amzn-mdamine commented Jan 27, 2025

Category

User level API features/changes

Describe the feature you'd like to request

Current Behavior

In Cedar, when evaluating policy expressions containing and, or, or if-else statements, the evaluation process stops after partially evaluating the left side of the expression. This partial evaluation can lead to missed opportunities to fully resolve the expression or resolve unknowns on the right side.

Proposed Enhancement

I propose adding a boolean flag to enable full evaluation of policy expressions. This enhancement would allow users to choose between the current partial evaluation behavior and a new full evaluation option.

Benefits

  1. More comprehensive results: Evaluating both sides of an expression can provide a complete picture of the policy's outcome.
  2. Improved resolution of unknowns: Full evaluation help resolve unknowns on the right side of expressions.
  3. Flexibility: Users can choose between partial and full evaluation based on their specific needs.

Implementation Details

Current Code (Example for And expression):

ExprKind::And { left, right } => {
    match self.partial_interpret(left, slots)? {
        PartialValue::Residual(e) => {
            Ok(PartialValue::Residual(Expr::and(e, right.as_ref().clone())))
        }
        PartialValue::Value(v) => {
            if v.get_as_bool()? {
                match self.partial_interpret(right, slots)? {
                    PartialValue::Residual(right) => {
                        Ok(PartialValue::Residual(Expr::and(Expr::val(true), right)))
                    }
                    PartialValue::Value(v) => Ok(v.get_as_bool()?.into()),
                }
            } else {
                Ok(false.into())
            }
        }
    }
}

Proposed pseudo code:

ExprKind::And { left, right } => {
    match self.partial_interpret(left, slots)? {
        PartialValue::Residual(left_residual) => {
            if self.full_evaluation {
                match self.partial_interpret(right, slots)? {
                    PartialValue::Residual(right_residual) => {
                        Ok(PartialValue::Residual(Expr::and(left_residual, right_residual)))
                    }
                    PartialValue::Value(rhs) => {
                        if rhs.get_as_bool()? {
                            Ok(PartialValue::Residual(Expr::and(left_residual, Expr::val(true))))
                        } else {
                            Ok(false.into())
                        }
                    }
                }
            } else {
                Ok(PartialValue::Residual(Expr::and(left_residual, right.as_ref().clone())))
            }
        }
        PartialValue::Value(v) => {
            // ... (rest of the existing code)
        }
    }
}

Current Code for eval_if:

fn eval_if(
    &self,
    guard: &Expr,
    consequent: &Arc<Expr>,
    alternative: &Arc<Expr>,
    slots: &SlotEnv,
) -> Result<PartialValue> {
    match self.partial_interpret(guard, slots)? {
        PartialValue::Value(v) => {
            if v.get_as_bool()? {
                self.partial_interpret(consequent, slots)
            } else {
                self.partial_interpret(alternative, slots)
            }
        }
        PartialValue::Residual(guard) => {
            Ok(Expr::ite_arc(Arc::new(guard), consequent.clone(), alternative.clone()).into())
        }
    }
}

Proposed pseudo code for eval_if:

fn clone_or_evaluate_expression(
    &self,
    expr: &Arc<Expr>,
    slots: &SlotEnv
) -> Result<Arc<Expr>> {
    if self.full_evaluation {
        match self.partial_interpret(expr, slots)? {
            PartialValue::Residual(e) => Ok(Arc::new(e)),
            PartialValue::Value(v) => Ok(Arc::new(v.into())),
        }
    } else {
        Ok(expr.clone())
    }
}

fn eval_if(
    &self,
    guard: &Expr,
    consequent: &Arc<Expr>,
    alternative: &Arc<Expr>,
    slots: &SlotEnv,
) -> Result<PartialValue> {
    match self.partial_interpret(guard, slots)? {
        PartialValue::Value(v) => {
            if v.get_as_bool()? {
                self.partial_interpret(consequent, slots)
            } else {
                self.partial_interpret(alternative, slots)
            }
        }
        PartialValue::Residual(guard) => {
            Ok(Expr::ite_arc(
                Arc::new(guard),
                self.clone_or_evaluate_expression(consequent, slots)?,
                self.clone_or_evaluate_expression(alternative, slots)?
            ).into())
        }
    }
}

Describe alternatives you've considered

There is no direct alternative to this approach that achieves the same goals.

Additional context

No response

Is this something that you'd be interested in working on?

  • 👋 I may be able to implement this feature request
  • ⚠️ This feature might incur a breaking change
@amzn-mdamine amzn-mdamine added feature-request This issue requets a substantial new feature pending-triage The cedar maintainers haven't looked at this yet. Automicaly added to all new issues. labels Jan 27, 2025
@cdisselkoen cdisselkoen removed the pending-triage The cedar maintainers haven't looked at this yet. Automicaly added to all new issues. label Feb 10, 2025
@cdisselkoen
Copy link
Contributor

This is highly related to RFC 95 -- any thoughts on that?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature-request This issue requets a substantial new feature
Projects
None yet
Development

No branches or pull requests

2 participants