diff --git a/README.md b/README.md index c2ef13d2c2..329fb2816c 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ Fides (*fee-dhez*, Latin: Fidēs) is an open-source tool that allows you to easi ## :rocket: Quick Start -1. Get running with Docker: First, ensure that you have `make` and `docker` installed locally, and clone the Fides repo. Then, from the fides directory, run the following commands: +1. Get running with Docker: First, ensure that you have `make` and `docker` installed locally, and clone the Fides repo. Then, from the fides directory, run the following commands:
@@ -113,7 +113,7 @@ Fides (*fee-dhez*, Latin: Fidēs) is an open-source tool that allows you to easi ```
- + Congratulations, you've successfully run your first fidesctl `evaluate` command! 3. Now, take a closer look at `demo_resources/demo_policy.yml` which describes an organization's privacy policy as code. This policy just includes one rule: fail if any system that uses contact information for marketing purposes. @@ -130,19 +130,18 @@ Fides (*fee-dhez*, Latin: Fidēs) is an open-source tool that allows you to easi name: Reject Direct Marketing description: Disallow collecting any user contact info to use for marketing. data_categories: - inclusion: ANY + matches: ANY values: - user.provided.identifiable.contact data_uses: - inclusion: ANY + matches: ANY values: - advertising data_subjects: - inclusion: ANY + matches: ANY values: - customer data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - action: REJECT ``` @@ -170,8 +169,8 @@ Fides (*fee-dhez*, Latin: Fidēs) is an open-source tool that allows you to easi
Run fidesctl evaluate again - - Re-run `fidesctl evaluate demo_resources` which will cause an evaluation failure! This is because your privacy policy has 1 rule that should fail if any system uses contact information for marketing purposes, and you've just updated your marketing system to start using contact information for marketing purposes. + + Re-run `fidesctl evaluate demo_resources` which will cause an evaluation failure! This is because your privacy policy has 1 rule that should fail if any system uses contact information for marketing purposes, and you've just updated your marketing system to start using contact information for marketing purposes. ```bash root@fa175a43c077:/fides/fidesctl# fidesctl evaluate demo_resources @@ -198,7 +197,7 @@ We are committed to fostering a safe and collaborative environment, such that al ### Documentation -For more information on getting started with Fides, how to configure and set up Fides, and more about the Fides ecosystem of open source projects: +For more information on getting started with Fides, how to configure and set up Fides, and more about the Fides ecosystem of open source projects: - Documentation: https://ethyca.github.io/fides/ - Tutorial: https://ethyca.github.io/fides/tutorial/ diff --git a/docs/fides/docs/language/resources/policy.md b/docs/fides/docs/language/resources/policy.md index 0b59956acf..145654cdec 100644 --- a/docs/fides/docs/language/resources/policy.md +++ b/docs/fides/docs/language/resources/policy.md @@ -1,6 +1,6 @@ # Policy -A Policy is your privacy policy as code, it lists a set of acceptable and non-acceptable rules and uses all 4 privacy attributes (`data_category`, `data_use`, `data_subject`, and `data_qualifier`). The purpose of the policy is to state what types of data are allowed for certain usages. +A Policy is your privacy policy as code, it lists a set of acceptable and non-acceptable rules and uses all 4 privacy attributes (`data_category`, `data_use`, `data_subject`, and `data_qualifier`). The purpose of the policy is to state what types of data are allowed for certain usages. ``` organization |-> ** policy ** @@ -11,7 +11,7 @@ A Policy is your privacy policy as code, it lists a set of acceptable and non-ac **fides_key**     _string_ -A string token of your own invention that uniquely identifies this Policy. It's your responsibility to ensure that the value is unique across all of your Policy objects. The value may only contain alphanumeric characters and underbars (`[A-Za-z0-9_]`). +A string token of your own invention that uniquely identifies this Policy. It's your responsibility to ensure that the value is unique across all of your Policy objects. The value may only contain alphanumeric characters and underbars (`[A-Za-z0-9_]`). **name**     _string_ @@ -35,23 +35,16 @@ The [Data Subjects](/fides/language/taxonomy/data_subjects/) privacy attribute d **data_qualifier**     _string_      -The [Data Qualifier](/fides/language/taxonomy/data_qualifiers/) privacy attribute describes the acceptable or non-acceptable level of deidentification for this data. +The [Data Qualifier](/fides/language/taxonomy/data_qualifiers/) privacy attribute describes the acceptable or non-acceptable level of deidentification for this data. -**inclusion**     _enum_      +**matches**     _enum_      * `ANY` * `ALL` * `NONE` +* `OTHER` -The inclusion criteria describes how you would like this rule to be evaluated. These basic logic gates determine whether the array of privacy attributes will be fully included (`ALL`), not included at all (`NONE`), or only included if at least 1 item in the array matches (`ANY`). - -**action**     _enum_      - -* `ACCEPT` -* `REJECT` -* `REQUIRE` - -The action describes how the policy should be enforced. These basic actions determine how the rule will be enforced. At the moment, `REJECT` is the only supported action, but ACCEPT and REQUIRE will be supported in version 1.0+. +The matches criteria describes how you would like this rule to be evaluated. These basic logic gates determine whether the array of privacy attributes will be fully included (`ALL`), not included at all (`NONE`), only included if at least 1 item in the array matches (`ANY`), or excluded with any additional attributes included (`OTHER`). **organization_fides_key**     _string_     default: `default_organization` @@ -72,19 +65,18 @@ policy: name: Reject Direct Marketing description: Disallow collecting any user contact info to use for marketing. data_categories: - inclusion: ANY + matches: ANY values: - user.provided.identifiable.contact data_uses: - inclusion: ANY + matches: ANY values: - advertising data_subjects: - inclusion: ANY + matches: ANY values: - customer data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - action: REJECT ``` **Demo manifest file:** `/fides/fidesctl/demo_resources/demo_policy.yml` @@ -105,25 +97,24 @@ POST /policy "name": "Reject Direct Marketing", "description": "Disallow collecting any user contact info to use for marketing.", "data_categories": { - "inclusion": "ANY", + "matches": "ANY", "values": [ "user.provided.identifiable.contact" ] }, "data_uses": { - "inclusion": "ANY", + "matches": "ANY", "values": [ "advertising" ] }, "data_subjects": { - "inclusion": "ANY", + "matches": "ANY", "values": [ "customer" ] }, - "data_qualifier": "aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified", - "action": "REJECT" + "data_qualifier": "aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified" } ] } diff --git a/docs/fides/docs/tutorial/policy.md b/docs/fides/docs/tutorial/policy.md index 208a9dc766..8221e7a612 100644 --- a/docs/fides/docs/tutorial/policy.md +++ b/docs/fides/docs/tutorial/policy.md @@ -14,12 +14,12 @@ policy: name: Minimize User Identifiable Data description: Reject collecting any user identifiable data for uses other than system operations data_categories: - inclusion: ANY + matches: ANY values: - user.provided.identifiable - user.derived.identifiable data_uses: - inclusion: ANY + matches: ANY values: - improve - personalize @@ -28,17 +28,16 @@ policy: - collect - train_ai_system data_subjects: - inclusion: ANY + matches: ANY values: - customer data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - action: REJECT - fides_key: reject_sensitive_data name: Reject Sensitive Data description: Reject collecting sensitive user data for any use data_categories: - inclusion: ANY + matches: ANY values: - user.provided.identifiable.biometric - user.provided.identifiable.childrens @@ -49,7 +48,7 @@ policy: - user.provided.identifiable.religious_belief - user.provided.identifiable.sexual_orientation data_uses: - inclusion: ANY + matches: ANY values: - provide - improve @@ -59,11 +58,10 @@ policy: - collect - train_ai_system data_subjects: - inclusion: ANY + matches: ANY values: - customer data_qualifier: aggregated - action: REJECT ``` This demo application is built without any real controls on user data, so the Fides policy is relatively restrictive. The two rules can be interpreted respectfully as: @@ -84,7 +82,6 @@ Policies use the following attributes: | data_uses | List[DataRule] | The various categories of data processing and operations within your organization | | data_subjects | List[DataRule] | The individual persons to whom you data rule pertains | | data_qualifier | String | The acceptable or non-acceptable level of deidentification | -| action | Choice | A string, either `ACCEPT` or `REJECT` | > For more detail on Policy resources, see the full [Policy resource documentation](../language/resources/policy.md). diff --git a/fidesctl/demo_resources/demo_policy.yml b/fidesctl/demo_resources/demo_policy.yml index b0528c8cf4..38b8bb6708 100644 --- a/fidesctl/demo_resources/demo_policy.yml +++ b/fidesctl/demo_resources/demo_policy.yml @@ -6,16 +6,15 @@ policy: - name: Reject Direct Marketing description: Disallow collecting any user contact info to use for marketing. data_categories: - inclusion: ANY + matches: ANY values: - user.provided.identifiable.contact data_uses: - inclusion: ANY + matches: ANY values: - advertising data_subjects: - inclusion: ANY + matches: ANY values: - customer data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - action: REJECT diff --git a/fidesctl/fides_resources/policy.yml b/fidesctl/fides_resources/policy.yml index a6d9e53589..a09d1f7d83 100644 --- a/fidesctl/fides_resources/policy.yml +++ b/fidesctl/fides_resources/policy.yml @@ -6,16 +6,15 @@ policy: - name: reject_non_system_data description: Disallow any non-system data or uses. data_categories: - inclusion: NONE + matches: OTHER values: - system.operations data_uses: - inclusion: NONE + matches: OTHER values: - provide data_subjects: - inclusion: NONE + matches: OTHER values: - anonymous_user data_qualifier: aggregated - action: REJECT diff --git a/fidesctl/src/fidesctl/core/evaluate.py b/fidesctl/src/fidesctl/core/evaluate.py index ba5a1c162a..ddb54d98f7 100644 --- a/fidesctl/src/fidesctl/core/evaluate.py +++ b/fidesctl/src/fidesctl/core/evaluate.py @@ -1,35 +1,34 @@ """Module for evaluating policies.""" -from typing import Dict, List, Optional, Set, Callable, cast - import uuid +from typing import Callable, Dict, List, Optional, Set, cast + from pydantic import AnyHttpUrl from fidesctl.cli.utils import handle_cli_response, pretty_echo from fidesctl.core import api -from fidesctl.core.api_helpers import get_server_resources, get_server_resource +from fidesctl.core.api_helpers import get_server_resource, get_server_resources from fidesctl.core.parse import parse from fidesctl.core.utils import echo_green, echo_red +from fideslang.default_taxonomy import DEFAULT_TAXONOMY from fideslang.models import ( - ActionEnum, - Evaluation, Dataset, - StatusEnum, - InclusionEnum, + Evaluation, + MatchesEnum, Policy, PolicyRule, PrivacyDeclaration, + StatusEnum, System, Taxonomy, Violation, ViolationAttributes, ) -from fideslang.default_taxonomy import DEFAULT_TAXONOMY -from fideslang.validation import FidesKey from fideslang.relationships import ( get_referenced_missing_keys, hydrate_missing_resources, ) from fideslang.utils import get_resource_by_fides_key +from fideslang.validation import FidesKey def get_evaluation_policies( @@ -108,23 +107,6 @@ def validate_policies_exist(policies: List[Policy], evaluate_fides_key: str) -> raise SystemExit(1) -def validate_supported_policy_rules(policies: List[Policy]) -> None: - """ - Validates that only supported actions are used in taxonomy. Currently - evaluations only support REJECT policy actions. - see: https://github.com/ethyca/fides/issues/150 - """ - for policy in policies: - for rule in policy.rules: - if rule.action != ActionEnum.REJECT: - echo_red( - "Policy ({}) uses unsupported policy action ({}). Only REJECT is currently supported".format( - policy.name, rule.action - ) - ) - raise SystemExit(1) - - def get_fides_key_parent_hierarchy( taxonomy: Taxonomy, fides_key: str ) -> List[FidesKey]: @@ -158,11 +140,11 @@ def get_fides_key_parent_hierarchy( def compare_rule_to_declaration( rule_types: List[FidesKey], declaration_type_hierarchies: List[List[FidesKey]], - rule_inclusion: InclusionEnum, + rule_match: MatchesEnum, ) -> Set[str]: """ Compare the list of fides_keys within the rule against the list - of fides_keys hierarchies from the declaration and uses the rule's inclusion + of fides_keys hierarchies from the declaration and uses the rule's matches field to determine whether the rule is triggered or not. Returns the offending keys, prioritizing the first descendant in the hierarchy. """ @@ -175,21 +157,22 @@ def compare_rule_to_declaration( else: mismatched_declaration_types.add(declared_declaration_type) - inclusion_map: Dict[InclusionEnum, Callable] = { - # any inclusion returns matching declared values as violations - InclusionEnum.ANY: lambda: matched_declaration_types, - # all inclusion returns matching declared values as violations if all values match rule values - InclusionEnum.ALL: lambda: matched_declaration_types + matches_map: Dict[MatchesEnum, Callable] = { + # any matches return matching declared values as violations + MatchesEnum.ANY: lambda: matched_declaration_types, + # all matches return matching declared values as violations if all values match rule values + MatchesEnum.ALL: lambda: matched_declaration_types if len(matched_declaration_types) == len(declaration_type_hierarchies) else set(), - # none inclusion returns mismatched declared values as violations if none of the values matched rule values - InclusionEnum.NONE: lambda: mismatched_declaration_types + # none matches return mismatched declared values as violations if none of the values matched rule values + MatchesEnum.NONE: lambda: mismatched_declaration_types if not any(matched_declaration_types) else set(), + # other matches return mismatched declared values as violations + MatchesEnum.OTHER: lambda: mismatched_declaration_types, } - inclusion_result = inclusion_map[rule_inclusion]() - return inclusion_result + return matches_map[rule_match]() def evaluate_policy_rule( @@ -215,7 +198,7 @@ def evaluate_policy_rule( data_category_violations = compare_rule_to_declaration( rule_types=policy_rule.data_categories.values, declaration_type_hierarchies=category_hierarchies, - rule_inclusion=policy_rule.data_categories.inclusion, + rule_match=policy_rule.data_categories.matches, ) # A declaration only has one data use, so its hierarchy gets put in a list @@ -225,14 +208,14 @@ def evaluate_policy_rule( data_use_violations = compare_rule_to_declaration( rule_types=policy_rule.data_uses.values, declaration_type_hierarchies=data_use_hierarchies, - rule_inclusion=policy_rule.data_uses.inclusion, + rule_match=policy_rule.data_uses.matches, ) # A data subject does not have a hierarchical structure data_subject_violations = compare_rule_to_declaration( rule_types=policy_rule.data_subjects.values, declaration_type_hierarchies=[[data_subject] for data_subject in data_subjects], - rule_inclusion=policy_rule.data_subjects.inclusion, + rule_match=policy_rule.data_subjects.matches, ) data_qualifier_violation = ( @@ -524,7 +507,6 @@ def evaluate( ) validate_policies_exist(policies=policies, evaluate_fides_key=policy_fides_key) - validate_supported_policy_rules(policies=policies) echo_green( "Evaluating the following policies:\n- {}".format( "\n- ".join([key.fides_key for key in policies]) diff --git a/fidesctl/src/fideslang/models.py b/fidesctl/src/fideslang/models.py index 4f64472586..ddf8e2fe1d 100644 --- a/fidesctl/src/fideslang/models.py +++ b/fidesctl/src/fideslang/models.py @@ -184,38 +184,27 @@ class Organization(FidesModel): # Policy -class InclusionEnum(str, Enum): +class MatchesEnum(str, Enum): """ - The InclusionEnum resouce model. + The MatchesEnum resouce model. - Determines how the listed resources are included in the evaluation logic. + Determines how the listed resources are matched in the evaluation logic. """ ANY = "ANY" ALL = "ALL" NONE = "NONE" - - -class ActionEnum(str, Enum): - """ - The ActionEnum resource model. - - Describes what the result of the PolicyRule should be if it is fulfilled. - """ - - ACCEPT = "ACCEPT" - REJECT = "REJECT" - REQUIRE = "REQUIRE" + OTHER = "OTHER" class PrivacyRule(BaseModel): """ The PrivacyRule resource model. - A list of privacy data types and what inclusion method to use. + A list of privacy data types and what match method to use. """ - inclusion: InclusionEnum + matches: MatchesEnum values: List[FidesKey] @@ -223,8 +212,7 @@ class PolicyRule(BaseModel): """ The PolicyRule resource model. - Describes combination of the various types of privacy data types - and what action that combination constitutes. + Describes the allowed combination of the various privacy data types. """ name: str @@ -234,7 +222,6 @@ class PolicyRule(BaseModel): data_qualifier: FidesKey = Field( default="aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified" ) - action: ActionEnum class Policy(FidesModel): diff --git a/fidesctl/tests/conftest.py b/fidesctl/tests/conftest.py index 72f61ce21a..8ab9e99cc3 100644 --- a/fidesctl/tests/conftest.py +++ b/fidesctl/tests/conftest.py @@ -124,11 +124,10 @@ def resources_dict(): ), "policy_rule": models.PolicyRule( name="Test Policy", - data_categories=models.PrivacyRule(inclusion="NONE", values=[]), - data_uses=models.PrivacyRule(inclusion="NONE", values=["provide.system"]), - data_subjects=models.PrivacyRule(inclusion="ANY", values=[]), + data_categories=models.PrivacyRule(matches="NONE", values=[]), + data_uses=models.PrivacyRule(matches="NONE", values=["provide.system"]), + data_subjects=models.PrivacyRule(matches="ANY", values=[]), data_qualifier="aggregated.anonymized.unlinked_pseudonymized.pseudonymized", - action="REJECT", ), "registry": models.Registry( organization_fides_key=1, diff --git a/fidesctl/tests/core/test_evaluate.py b/fidesctl/tests/core/test_evaluate.py index 08a868020d..fa8e2d8515 100644 --- a/fidesctl/tests/core/test_evaluate.py +++ b/fidesctl/tests/core/test_evaluate.py @@ -1,25 +1,22 @@ -from unittest.mock import patch, MagicMock -import pytest - from typing import List +from unittest.mock import MagicMock, patch -from fidesctl.core import evaluate, api as _api +import pytest +from fidesctl.core import evaluate from fideslang.models import ( DataCategory, DataQualifier, - DataSubject, - DataUse, Dataset, DatasetCollection, + DataSubject, + DataUse, + MatchesEnum, Policy, - PrivacyRule, - PrivacyDeclaration, - Taxonomy, PolicyRule, - InclusionEnum, - ActionEnum, + PrivacyDeclaration, System, + Taxonomy, ) @@ -62,27 +59,6 @@ def evaluation_hierarchical_key_basic_taxonomy(): ) -def create_policy_rule_with_action( - policy_rule_key: str, action: ActionEnum -) -> PolicyRule: - return PolicyRule( - name=policy_rule_key, - action=action, - data_categories={ - "values": ["data_category_1"], - "inclusion": InclusionEnum.ANY, - }, - data_uses={ - "values": ["data_use_1"], - "inclusion": InclusionEnum.ANY, - }, - data_subjects={ - "values": ["data_subject_1"], - "inclusion": InclusionEnum.ANY, - }, - ) - - def create_policy_rule_with_keys( data_categories: List[str], data_uses: List[str], @@ -93,18 +69,17 @@ def create_policy_rule_with_keys( name="policy_rule_1", data_categories={ "values": data_categories, - "inclusion": InclusionEnum.ANY, + "matches": MatchesEnum.ANY, }, data_uses={ "values": data_uses, - "inclusion": InclusionEnum.ANY, + "matches": MatchesEnum.ANY, }, data_subjects={ "values": data_subjects, - "inclusion": InclusionEnum.ANY, + "matches": MatchesEnum.ANY, }, data_qualifier=data_qualifier, - action=ActionEnum.REJECT, ) @@ -294,7 +269,7 @@ def test_compare_rule_to_declaration_any_true(): result = evaluate.compare_rule_to_declaration( rule_types=["key_1"], declaration_type_hierarchies=[["key_2"], ["key_1"]], - rule_inclusion="ANY", + rule_match="ANY", ) assert {"key_1"} == result @@ -304,7 +279,7 @@ def test_compare_rule_to_declaration_any_true_hierarchical(): result = evaluate.compare_rule_to_declaration( rule_types=["key_1_parent"], declaration_type_hierarchies=[["key_2"], ["key_1", "key_1_parent"]], - rule_inclusion="ANY", + rule_match="ANY", ) assert {"key_1"} == result @@ -314,7 +289,7 @@ def test_compare_rule_to_declaration_any_false(): result = evaluate.compare_rule_to_declaration( rule_types=["key_1"], declaration_type_hierarchies=[["key_2"], ["key_3"]], - rule_inclusion="ANY", + rule_match="ANY", ) assert not result @@ -324,7 +299,7 @@ def test_compare_rule_to_declaration_any_false_hierarchical(): result = evaluate.compare_rule_to_declaration( rule_types=["key_1"], declaration_type_hierarchies=[["key_2", "key_2_parent"], ["key_3"]], - rule_inclusion="ANY", + rule_match="ANY", ) assert not result @@ -334,7 +309,7 @@ def test_compare_rule_to_declaration_all_true(): result = evaluate.compare_rule_to_declaration( rule_types=["key_1", "key_3"], declaration_type_hierarchies=[["key_3"], ["key_1"]], - rule_inclusion="ALL", + rule_match="ALL", ) assert {"key_3", "key_1"} == result @@ -347,7 +322,7 @@ def test_compare_rule_to_declaration_all_true_hierarchical(): ["key_3", "key_3_parent"], ["key_1", "key_1_parent"], ], - rule_inclusion="ALL", + rule_match="ALL", ) assert {"key_3", "key_1"} == result @@ -357,7 +332,7 @@ def test_compare_rule_to_declaration_all_false(): result = evaluate.compare_rule_to_declaration( rule_types=["key_1", "key_3"], declaration_type_hierarchies=[["key_2"], ["key_1"]], - rule_inclusion="ALL", + rule_match="ALL", ) assert not result @@ -366,8 +341,8 @@ def test_compare_rule_to_declaration_all_false(): def test_compare_rule_to_declaration_all_false_hierarchical(): result = evaluate.compare_rule_to_declaration( rule_types=["key_1", "key_1_parent", "key_3"], - declaration_type_hierarchies=[["key_2"], ["key_1" "key_1_parent"]], - rule_inclusion="ALL", + declaration_type_hierarchies=[["key_2"], ["key_1", "key_1_parent"]], + rule_match="ALL", ) assert not result @@ -377,7 +352,7 @@ def test_compare_rule_to_declaration_none_true(): result = evaluate.compare_rule_to_declaration( rule_types=["key_1"], declaration_type_hierarchies=[["key_2"], ["key_3"]], - rule_inclusion="NONE", + rule_match="NONE", ) assert {"key_2", "key_3"} == result @@ -387,7 +362,7 @@ def test_compare_rule_to_declaration_none_true_hierarchical(): result = evaluate.compare_rule_to_declaration( rule_types=["key_1"], declaration_type_hierarchies=[["key_2", "key_2_parent"], ["key_3"]], - rule_inclusion="NONE", + rule_match="NONE", ) assert {"key_2", "key_3"} == result @@ -397,7 +372,7 @@ def test_compare_rule_to_declaration_none_false(): result = evaluate.compare_rule_to_declaration( rule_types=["key_1"], declaration_type_hierarchies=[["key_2"], ["key_3"], ["key_1"]], - rule_inclusion="NONE", + rule_match="NONE", ) assert not result @@ -407,7 +382,47 @@ def test_compare_rule_to_declaration_none_false_hierarchical(): result = evaluate.compare_rule_to_declaration( rule_types=["key_1_parent"], declaration_type_hierarchies=[["key_2"], ["key_3"], ["key_1", "key_1_parent"]], - rule_inclusion="NONE", + rule_match="NONE", + ) + assert not result + + +@pytest.mark.unit +def test_compare_rule_to_declaration_other_true(): + result = evaluate.compare_rule_to_declaration( + rule_types=["key_1"], + declaration_type_hierarchies=[["key_2"], ["key_1"]], + rule_match="OTHER", + ) + assert {"key_2"} == result + + +@pytest.mark.unit +def test_compare_rule_to_declaration_other_true_hierarchical(): + result = evaluate.compare_rule_to_declaration( + rule_types=["key_1_parent"], + declaration_type_hierarchies=[["key_2"], ["key_1", "key_1_parent"]], + rule_match="OTHER", + ) + assert {"key_2"} == result + + +@pytest.mark.unit +def test_compare_rule_to_declaration_other_false(): + result = evaluate.compare_rule_to_declaration( + rule_types=["key_1", "key_3"], + declaration_type_hierarchies=[["key_1"], ["key_3"]], + rule_match="OTHER", + ) + assert not result + + +@pytest.mark.unit +def test_compare_rule_to_declaration_other_false_hierarchical(): + result = evaluate.compare_rule_to_declaration( + rule_types=["key_1", "key_3_parent"], + declaration_type_hierarchies=[["key_1"], ["key_3", "key_3_parent"]], + rule_match="OTHER", ) assert not result @@ -440,45 +455,6 @@ def test_get_dataset_by_fides_key_does_not_exist(): assert not result -@pytest.mark.unit -def test_validate_supported_policy_rules_throws_with_unsupported_action(): - with pytest.raises(SystemExit): - evaluate.validate_supported_policy_rules( - policies=[ - Policy( - fides_key="policy_1", - rules=[ - create_policy_rule_with_action( - policy_rule_key="policy_rule_1", action=ActionEnum.ACCEPT - ), - create_policy_rule_with_action( - policy_rule_key="policy_rule_2", action=ActionEnum.REJECT - ), - ], - ) - ], - ) - - -@pytest.mark.unit -def test_validate_supported_policy_rules_passes(): - evaluate.validate_supported_policy_rules( - policies=[ - Policy( - fides_key="policy_1", - rules=[ - create_policy_rule_with_action( - policy_rule_key="policy_rule_1", action=ActionEnum.REJECT - ), - create_policy_rule_with_action( - policy_rule_key="policy_rule_2", action=ActionEnum.REJECT - ), - ], - ) - ], - ) - - @pytest.mark.unit def test_get_fides_key_parent_hierarchy_child( evaluation_hierarchical_key_basic_taxonomy, diff --git a/fidesctl/tests/data/failing_dataset_collection_taxonomy.yml b/fidesctl/tests/data/failing_dataset_collection_taxonomy.yml index 86db842dae..6d176d4f61 100644 --- a/fidesctl/tests/data/failing_dataset_collection_taxonomy.yml +++ b/fidesctl/tests/data/failing_dataset_collection_taxonomy.yml @@ -40,16 +40,15 @@ policy: - fides_key: reject_political_opinion description: Disallow advertising of customer political opinion data data_categories: - inclusion: ANY + matches: ANY values: - user.provided.identifiable.political_opinion data_uses: - inclusion: ANY + matches: ANY values: - advertising data_subjects: - inclusion: ANY + matches: ANY values: - customer data_qualifier: aggregated - action: REJECT \ No newline at end of file diff --git a/fidesctl/tests/data/failing_dataset_field_taxonomy.yml b/fidesctl/tests/data/failing_dataset_field_taxonomy.yml index 1a895ab0ac..d91d585e5f 100644 --- a/fidesctl/tests/data/failing_dataset_field_taxonomy.yml +++ b/fidesctl/tests/data/failing_dataset_field_taxonomy.yml @@ -41,16 +41,15 @@ policy: - fides_key: reject_political_opinion description: Disallow advertising of customer political opinion data data_categories: - inclusion: ANY + matches: ANY values: - user.provided.identifiable.political_opinion data_uses: - inclusion: ANY + matches: ANY values: - advertising data_subjects: - inclusion: ANY + matches: ANY values: - customer data_qualifier: aggregated - action: REJECT \ No newline at end of file diff --git a/fidesctl/tests/data/failing_dataset_taxonomy.yml b/fidesctl/tests/data/failing_dataset_taxonomy.yml index 449b907576..4b5f252813 100644 --- a/fidesctl/tests/data/failing_dataset_taxonomy.yml +++ b/fidesctl/tests/data/failing_dataset_taxonomy.yml @@ -40,16 +40,15 @@ policy: - fides_key: reject_political_opinion description: Disallow advertising of customer political opinion data data_categories: - inclusion: ANY + matches: ANY values: - user.provided.identifiable.political_opinion data_uses: - inclusion: ANY + matches: ANY values: - advertising data_subjects: - inclusion: ANY + matches: ANY values: - customer data_qualifier: aggregated - action: REJECT \ No newline at end of file diff --git a/fidesctl/tests/data/failing_declaration_taxonomy.yml b/fidesctl/tests/data/failing_declaration_taxonomy.yml index 4e0791a0d5..a081fe8aed 100644 --- a/fidesctl/tests/data/failing_declaration_taxonomy.yml +++ b/fidesctl/tests/data/failing_declaration_taxonomy.yml @@ -21,16 +21,15 @@ policy: - name: reject_targeted_marketing description: Disallow third party sharing of customer data data_categories: - inclusion: ANY + matches: ANY values: - user.provided data_uses: - inclusion: ANY + matches: ANY values: - third_party_sharing data_subjects: - inclusion: ANY + matches: ANY values: - customer data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - action: REJECT diff --git a/fidesctl/tests/data/passing_declaration_taxonomy.yml b/fidesctl/tests/data/passing_declaration_taxonomy.yml index 915a97c065..59ab86d552 100644 --- a/fidesctl/tests/data/passing_declaration_taxonomy.yml +++ b/fidesctl/tests/data/passing_declaration_taxonomy.yml @@ -21,16 +21,15 @@ policy: - name: reject_targeted_marketing description: Disallow advertising of customer data data_categories: - inclusion: ANY + matches: ANY values: - user.provided data_uses: - inclusion: ANY + matches: ANY values: - advertising data_subjects: - inclusion: ANY + matches: ANY values: - customer data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - action: REJECT diff --git a/fidesctl/tests/lang/test_models.py b/fidesctl/tests/lang/test_models.py index 4b795b5a62..e984df88bd 100644 --- a/fidesctl/tests/lang/test_models.py +++ b/fidesctl/tests/lang/test_models.py @@ -143,57 +143,37 @@ def test_fides_model_fides_key_invalid(): @pytest.mark.unit def test_valid_privacy_rule(): - privacy_rule = PrivacyRule(inclusion="ANY", values=["foo_bar"]) + privacy_rule = PrivacyRule(matches="ANY", values=["foo_bar"]) assert privacy_rule @pytest.mark.unit def test_invalid_fides_key_privacy_rule(): with pytest.raises(FidesValidationError): - PrivacyRule(inclusion="ANY", values=["foo-bar"]) + PrivacyRule(matches="ANY", values=["foo-bar"]) assert True @pytest.mark.unit -def test_invalid_inclusion_privacy_rule(): +def test_invalid_matches_privacy_rule(): with pytest.raises(ValidationError): - PrivacyRule(inclusion="AN", values=["foo_bar"]) + PrivacyRule(matches="AN", values=["foo_bar"]) assert True @pytest.mark.unit def test_valid_policy_rule(): - PolicyRule( + assert PolicyRule( organization_fides_key=1, policyId=1, fides_key="test_policy", name="Test Policy", description="Test Policy", - data_categories=PrivacyRule(inclusion="NONE", values=[]), - data_uses=PrivacyRule(inclusion="NONE", values=["provide.system"]), - data_subjects=PrivacyRule(inclusion="ANY", values=[]), + data_categories=PrivacyRule(matches="NONE", values=[]), + data_uses=PrivacyRule(matches="NONE", values=["provide.system"]), + data_subjects=PrivacyRule(matches="ANY", values=[]), data_qualifier="aggregated.anonymized.unlinked_pseudonymized.pseudonymized", - action="REJECT", - ), - assert True - - -@pytest.mark.unit -def test_invalid_action_enum_policy_rule(): - with pytest.raises(ValidationError): - PolicyRule( - organization_fides_key=1, - policyId=1, - fides_key="test_policy", - name="Test Policy", - description="Test Policy", - data_categories=PrivacyRule(inclusion="NONE", values=[]), - data_uses=PrivacyRule(inclusion="NONE", values=["provide.system"]), - data_subjects=PrivacyRule(inclusion="ANY", values=[]), - data_qualifier="aggregated.anonymized.unlinked_pseudonymized.pseudonymized", - action="REJT", - ), - assert True + ) @pytest.mark.unit diff --git a/fidesctl/tests/lang/test_relationships.py b/fidesctl/tests/lang/test_relationships.py index b51edc797e..55d157c316 100644 --- a/fidesctl/tests/lang/test_relationships.py +++ b/fidesctl/tests/lang/test_relationships.py @@ -1,20 +1,17 @@ import pytest from fideslang import relationships - from fideslang.models import ( DataCategory, - System, - Taxonomy, - Policy, Dataset, - PolicyRule, - PrivacyRule, DatasetCollection, DatasetField, + MatchesEnum, + Policy, + PolicyRule, PrivacyDeclaration, - InclusionEnum, - ActionEnum, + System, + Taxonomy, ) @@ -120,18 +117,17 @@ def test_get_referenced_missing_policy_keys(): rules=[ PolicyRule( name="policy_rule_1", - action=ActionEnum.REJECT, data_categories={ "values": ["policy_rule_data_category_1"], - "inclusion": InclusionEnum.ANY, + "matches": MatchesEnum.ANY, }, data_uses={ "values": ["policy_rule_data_use_1"], - "inclusion": InclusionEnum.ANY, + "matches": MatchesEnum.ANY, }, data_subjects={ "values": ["policy_rule_data_subject_1"], - "inclusion": InclusionEnum.ANY, + "matches": MatchesEnum.ANY, }, data_qualifier="policy_rule_data_qualifier_1", )