-
Notifications
You must be signed in to change notification settings - Fork 86
Eng 2195 be policy evaluation engine #7253
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
base: main
Are you sure you want to change the base?
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub. 2 Skipped Deployments
|
Greptile OverviewGreptile SummaryCreated a new policy evaluation engine that evaluates Key Changes:
Issues Found:
Confidence Score: 4/5
Important Files Changed
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
1 file reviewed, 1 comment
src/fides/api/task/conditional_dependencies/policy_evaluation.py
Outdated
Show resolved
Hide resolved
|
@greptile please review |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
4 files reviewed, 4 comments
src/fides/api/task/conditional_dependencies/policy_evaluation.py
Outdated
Show resolved
Hide resolved
src/fides/api/task/conditional_dependencies/policy_evaluation.py
Outdated
Show resolved
Hide resolved
tests/api/task/conditional_dependencies/test_policy_evaluation.py
Outdated
Show resolved
Hide resolved
…thyca/fides into ENG-2195-be-policy-evaluation-engine
|
@greptile please review |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No files reviewed, no comments
tests/api/task/conditional_dependencies/test_policy_evaluation.py
Outdated
Show resolved
Hide resolved
| logger.error( | ||
| f"Error evaluating policy {policy_condition.policy.key}: " | ||
| f"{type(exc).__name__}: {exc}", | ||
| exc_info=True, | ||
| ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is this equivalent to using logger.exception ? will this include a stack trace in dev envs? (and what about prod ones?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated to use exception
| # Default to access if no action_type provided | ||
| return _get_default_policy_result( | ||
| db, action_type or ActionType.access | ||
| ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have little context on the policy conditions, but why is access the default?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updating to make Action type not optional :)
| root_condition = ConditionTypeAdapter.validate_python( | ||
| policy_condition.condition_tree | ||
| ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm slightly confused as to what this is doing here, I thought now we had the entire condition tree on the root node?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I updated the name to be more clear. This is loading the json version of a condition tree into the Condition schema.
| return PolicyEvaluationResult( | ||
| policy=policy, evaluation_result=None, is_default=True | ||
| ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't follow why we need the "default policy" if we're just returning None for the result ? can't we just leave policy as None as well ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is evaluating conditions to select a policy - so we need to return a policy. The evaluation result is the set of conditions which matched for logging purposes.
For defaults there was no set of conditions that matched, its just the default (fallback)
| db, action_type or ActionType.access | ||
| ) | ||
|
|
||
| evaluator = ConditionEvaluator(db) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what do you think of having a PolicyEvaluator class that contains a evaluate_policy_conditions method , instead of just having it be a function?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have no issue with that, refactoring to make it a class. :)
| assert result.policy.key == "conditional" | ||
|
|
||
|
|
||
| class TestEdgeCases: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: I don't love "TestEdgeCases" as a test suite name hah , arguably both the tests in this class can be moved into TestDefaultFallback ?
|
@greptile please review |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
4 files reviewed, 2 comments
| query = ( | ||
| self.db.query(PolicyCondition) | ||
| .join(Policy, PolicyCondition.policy_id == Policy.id) | ||
| .options(contains_eager(PolicyCondition.policy)) | ||
| .join(Rule, Policy.id == Rule.policy_id) | ||
| .filter(Rule.action_type == action_type) | ||
| ) | ||
| return query.all() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
query doesn't specify ordering - when multiple policies match, the result is non-deterministic
add explicit ordering (e.g. by created_at or a dedicated priority field) to ensure consistent policy selection
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is a check to prevent multiple policies from having the same conditions. There should be only 1 match.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could return query.one() so if at any point this somehow returns multiple ones, we get a failure :)
| @pytest.mark.asyncio | ||
| @pytest.fixture(scope="function") | ||
| def seed_data(session): | ||
| def seed_data(db: Session): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is this change related?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wanted to use seed data to get all of the premade policies but when I used this fixture I got an error saying there was no session fixture. Pretty sure no other tests were using this or we would have seen a lot more errors!
erosselli
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Approved, left two comments
Ticket ENG-2195
Description Of Changes
🎯 Create a Policy Evaluation Engine for Fides
This PR creates a new policy evaluation engine to accept a PrivacyRequest object transform it to evaluation data dictionary then compare to policies with conditions. For each policy, check if conditions match and return the matching policy + evaluation result. There should also be a fallback to default if no policies match. There is a check in place when creating a condition to validate there are no identical conditions. So there should be 1 or 0 matches.
Code Changes
src/fides/api/task/conditional_dependencies/policy_evaluation.py- new enginesrc/fides/api/task/conditional_dependencies/util.pyadded field address extraction functionsrc/fides/api/task/manual/manual_task_conditional_evaluation.pyupdated to import new functionsrc/fides/api/task/manual/manual_task_utils.pyupdated to use new functiontests/api/task/conditional_dependencies/test_policy_evaluation.pytests!Steps to Confirm
Pre-Merge Checklist
CHANGELOG.mdupdatedmaindowngrade()migration is correct and works